Files
git.stella-ops.org/src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace/Serialization/EntryTraceGraphSerializer.cs
master f98cea3bcf Add Authority Advisory AI and API Lifecycle Configuration
- Introduced AuthorityAdvisoryAiOptions and related classes for managing advisory AI configurations, including remote inference options and tenant-specific settings.
- Added AuthorityApiLifecycleOptions to control API lifecycle settings, including legacy OAuth endpoint configurations.
- Implemented validation and normalization methods for both advisory AI and API lifecycle options to ensure proper configuration.
- Created AuthorityNotificationsOptions and its related classes for managing notification settings, including ack tokens, webhooks, and escalation options.
- Developed IssuerDirectoryClient and related models for interacting with the issuer directory service, including caching mechanisms and HTTP client configurations.
- Added support for dependency injection through ServiceCollectionExtensions for the Issuer Directory Client.
- Updated project file to include necessary package references for the new Issuer Directory Client library.
2025-11-02 13:50:25 +02:00

310 lines
12 KiB
C#

using System.Collections.Immutable;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace StellaOps.Scanner.EntryTrace.Serialization;
public static class EntryTraceGraphSerializer
{
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web)
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
WriteIndented = false
};
static EntryTraceGraphSerializer()
{
SerializerOptions.Converters.Add(new JsonStringEnumConverter());
}
public static string Serialize(EntryTraceGraph graph)
{
ArgumentNullException.ThrowIfNull(graph);
var contract = EntryTraceGraphContract.FromGraph(graph);
return JsonSerializer.Serialize(contract, SerializerOptions);
}
public static EntryTraceGraph Deserialize(string json)
{
ArgumentException.ThrowIfNullOrWhiteSpace(json);
var contract = JsonSerializer.Deserialize<EntryTraceGraphContract>(json, SerializerOptions)
?? throw new InvalidOperationException("Failed to deserialize EntryTrace graph.");
return contract.ToGraph();
}
private sealed class EntryTraceGraphContract
{
public EntryTraceOutcome Outcome { get; set; }
public List<EntryTraceNodeContract> Nodes { get; set; } = new();
public List<EntryTraceEdgeContract> Edges { get; set; } = new();
public List<EntryTraceDiagnosticContract> Diagnostics { get; set; } = new();
public List<EntryTracePlanContract> Plans { get; set; } = new();
public List<EntryTraceTerminalContract> Terminals { get; set; } = new();
public static EntryTraceGraphContract FromGraph(EntryTraceGraph graph)
{
return new EntryTraceGraphContract
{
Outcome = graph.Outcome,
Nodes = graph.Nodes.Select(EntryTraceNodeContract.FromNode).ToList(),
Edges = graph.Edges.Select(EntryTraceEdgeContract.FromEdge).ToList(),
Diagnostics = graph.Diagnostics.Select(EntryTraceDiagnosticContract.FromDiagnostic).ToList(),
Plans = graph.Plans.Select(EntryTracePlanContract.FromPlan).ToList(),
Terminals = graph.Terminals.Select(EntryTraceTerminalContract.FromTerminal).ToList()
};
}
public EntryTraceGraph ToGraph()
{
return new EntryTraceGraph(
Outcome,
Nodes.Select(n => n.ToNode()).ToImmutableArray(),
Edges.Select(e => e.ToEdge()).ToImmutableArray(),
Diagnostics.Select(d => d.ToDiagnostic()).ToImmutableArray(),
Plans.Select(p => p.ToPlan()).ToImmutableArray(),
Terminals.Select(t => t.ToTerminal()).ToImmutableArray());
}
}
private sealed class EntryTraceNodeContract
{
public int Id { get; set; }
public EntryTraceNodeKind Kind { get; set; }
public string DisplayName { get; set; } = string.Empty;
public List<string> Arguments { get; set; } = new();
public EntryTraceInterpreterKind InterpreterKind { get; set; }
public EntryTraceEvidenceContract? Evidence { get; set; }
public EntryTraceSpanContract? Span { get; set; }
public Dictionary<string, string>? Metadata { get; set; }
public static EntryTraceNodeContract FromNode(EntryTraceNode node)
{
return new EntryTraceNodeContract
{
Id = node.Id,
Kind = node.Kind,
DisplayName = node.DisplayName,
Arguments = node.Arguments.ToList(),
InterpreterKind = node.InterpreterKind,
Evidence = node.Evidence is null ? null : EntryTraceEvidenceContract.FromEvidence(node.Evidence),
Span = node.Span is null ? null : EntryTraceSpanContract.FromSpan(node.Span.Value),
Metadata = node.Metadata?.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal)
};
}
public EntryTraceNode ToNode()
{
return new EntryTraceNode(
Id,
Kind,
DisplayName,
Arguments.ToImmutableArray(),
InterpreterKind,
Evidence?.ToEvidence(),
Span?.ToSpan(),
Metadata is null ? null : Metadata.ToImmutableDictionary(StringComparer.Ordinal));
}
}
private sealed class EntryTraceEdgeContract
{
public int From { get; set; }
public int To { get; set; }
public string Relationship { get; set; } = string.Empty;
public Dictionary<string, string>? Metadata { get; set; }
public static EntryTraceEdgeContract FromEdge(EntryTraceEdge edge)
{
return new EntryTraceEdgeContract
{
From = edge.FromNodeId,
To = edge.ToNodeId,
Relationship = edge.Relationship,
Metadata = edge.Metadata?.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal)
};
}
public EntryTraceEdge ToEdge()
{
return new EntryTraceEdge(
From,
To,
Relationship,
Metadata is null ? null : Metadata.ToImmutableDictionary(StringComparer.Ordinal));
}
}
private sealed class EntryTraceDiagnosticContract
{
public EntryTraceDiagnosticSeverity Severity { get; set; }
public EntryTraceUnknownReason Reason { get; set; }
public string Message { get; set; } = string.Empty;
public EntryTraceSpanContract? Span { get; set; }
public string? RelatedPath { get; set; }
public static EntryTraceDiagnosticContract FromDiagnostic(EntryTraceDiagnostic diagnostic)
{
return new EntryTraceDiagnosticContract
{
Severity = diagnostic.Severity,
Reason = diagnostic.Reason,
Message = diagnostic.Message,
Span = diagnostic.Span is null ? null : EntryTraceSpanContract.FromSpan(diagnostic.Span.Value),
RelatedPath = diagnostic.RelatedPath
};
}
public EntryTraceDiagnostic ToDiagnostic()
{
return new EntryTraceDiagnostic(
Severity,
Reason,
Message,
Span?.ToSpan(),
RelatedPath);
}
}
private sealed class EntryTracePlanContract
{
public List<string> Command { get; set; } = new();
public Dictionary<string, string> Environment { get; set; } = new();
public string WorkingDirectory { get; set; } = string.Empty;
public string User { get; set; } = string.Empty;
public string TerminalPath { get; set; } = string.Empty;
public EntryTraceTerminalType Type { get; set; }
public string? Runtime { get; set; }
public double Confidence { get; set; }
public Dictionary<string, string> Evidence { get; set; } = new();
public static EntryTracePlanContract FromPlan(EntryTracePlan plan)
{
return new EntryTracePlanContract
{
Command = plan.Command.ToList(),
Environment = plan.Environment.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal),
WorkingDirectory = plan.WorkingDirectory,
User = plan.User,
TerminalPath = plan.TerminalPath,
Type = plan.Type,
Runtime = plan.Runtime,
Confidence = plan.Confidence,
Evidence = plan.Evidence.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal)
};
}
public EntryTracePlan ToPlan()
{
return new EntryTracePlan(
Command.ToImmutableArray(),
Environment.ToImmutableDictionary(StringComparer.Ordinal),
WorkingDirectory,
User,
TerminalPath,
Type,
Runtime,
Confidence,
Evidence.ToImmutableDictionary(StringComparer.Ordinal));
}
}
private sealed class EntryTraceTerminalContract
{
public string Path { get; set; } = string.Empty;
public EntryTraceTerminalType Type { get; set; }
public string? Runtime { get; set; }
public double Confidence { get; set; }
public Dictionary<string, string> Evidence { get; set; } = new();
public string User { get; set; } = string.Empty;
public string WorkingDirectory { get; set; } = string.Empty;
public List<string> Arguments { get; set; } = new();
public static EntryTraceTerminalContract FromTerminal(EntryTraceTerminal terminal)
{
return new EntryTraceTerminalContract
{
Path = terminal.Path,
Type = terminal.Type,
Runtime = terminal.Runtime,
Confidence = terminal.Confidence,
Evidence = terminal.Evidence.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal),
User = terminal.User,
WorkingDirectory = terminal.WorkingDirectory,
Arguments = terminal.Arguments.ToList()
};
}
public EntryTraceTerminal ToTerminal()
{
return new EntryTraceTerminal(
Path,
Type,
Runtime,
Confidence,
Evidence.ToImmutableDictionary(StringComparer.Ordinal),
User,
WorkingDirectory,
Arguments.ToImmutableArray());
}
}
private sealed class EntryTraceEvidenceContract
{
public string Path { get; set; } = string.Empty;
public string? Layer { get; set; }
public string? Source { get; set; }
public Dictionary<string, string>? Metadata { get; set; }
public static EntryTraceEvidenceContract FromEvidence(EntryTraceEvidence evidence)
{
return new EntryTraceEvidenceContract
{
Path = evidence.Path,
Layer = evidence.LayerDigest,
Source = evidence.Source,
Metadata = evidence.Metadata?.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal)
};
}
public EntryTraceEvidence ToEvidence()
{
return new EntryTraceEvidence(
Path,
Layer,
Source ?? string.Empty,
Metadata is null ? null : new Dictionary<string, string>(Metadata, StringComparer.Ordinal));
}
}
private sealed class EntryTraceSpanContract
{
public string? Path { get; set; }
public int StartLine { get; set; }
public int StartColumn { get; set; }
public int EndLine { get; set; }
public int EndColumn { get; set; }
public static EntryTraceSpanContract FromSpan(EntryTraceSpan span)
{
return new EntryTraceSpanContract
{
Path = span.Path,
StartLine = span.StartLine,
StartColumn = span.StartColumn,
EndLine = span.EndLine,
EndColumn = span.EndColumn
};
}
public EntryTraceSpan ToSpan()
{
return new EntryTraceSpan(
Path,
StartLine,
StartColumn,
EndLine,
EndColumn);
}
}
}