- 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.
310 lines
12 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|