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.
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user