// ----------------------------------------------------------------------------- // RichGraphStatement.cs // Sprint: SPRINT_3801_0001_0002_richgraph_attestation // Description: In-toto statement for RichGraph attestations. // ----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Text.Json.Serialization; namespace StellaOps.Scanner.WebService.Contracts; /// /// In-toto statement for RichGraph computation attestations. /// Predicate type: stella.ops/richgraph@v1 /// /// /// This statement attests that a RichGraph was computed from a specific /// SBOM and call graph, producing a content-addressed graph digest. /// public sealed record RichGraphStatement { /// /// The statement type, always "https://in-toto.io/Statement/v1". /// [JsonPropertyName("_type")] public string Type => "https://in-toto.io/Statement/v1"; /// /// The subjects this statement is about (scan + graph artifacts). /// [JsonPropertyName("subject")] public required IReadOnlyList Subject { get; init; } /// /// The predicate type URI. /// [JsonPropertyName("predicateType")] public string PredicateType => "stella.ops/richgraph@v1"; /// /// The RichGraph predicate payload. /// [JsonPropertyName("predicate")] public required RichGraphPredicate Predicate { get; init; } } /// /// Subject in a RichGraph statement. /// public sealed record RichGraphSubject { /// /// The name or identifier of the subject (e.g., scan ID, graph ID). /// [JsonPropertyName("name")] public required string Name { get; init; } /// /// Digests of the subject in algorithm:hex format. /// [JsonPropertyName("digest")] public required IReadOnlyDictionary Digest { get; init; } } /// /// Predicate payload for RichGraph attestations. /// public sealed record RichGraphPredicate { /// /// The RichGraph identifier. /// [JsonPropertyName("graph_id")] public required string GraphId { get; init; } /// /// Content-addressed digest of the RichGraph. /// [JsonPropertyName("graph_digest")] public required string GraphDigest { get; init; } /// /// Number of nodes in the graph. /// [JsonPropertyName("node_count")] public required int NodeCount { get; init; } /// /// Number of edges in the graph. /// [JsonPropertyName("edge_count")] public required int EdgeCount { get; init; } /// /// Number of root nodes (entrypoints) in the graph. /// [JsonPropertyName("root_count")] public required int RootCount { get; init; } /// /// Information about the analyzer that computed the graph. /// [JsonPropertyName("analyzer")] public required RichGraphAnalyzerInfo Analyzer { get; init; } /// /// When the graph was computed (UTC ISO 8601). /// [JsonPropertyName("computed_at")] public required DateTimeOffset ComputedAt { get; init; } /// /// When the graph attestation expires (UTC ISO 8601). /// [JsonPropertyName("expires_at")] public DateTimeOffset? ExpiresAt { get; init; } /// /// Reference to the source SBOM (digest). /// [JsonPropertyName("sbom_ref")] public string? SbomRef { get; init; } /// /// Reference to the source call graph (digest). /// [JsonPropertyName("callgraph_ref")] public string? CallgraphRef { get; init; } /// /// Language of the analyzed code. /// [JsonPropertyName("language")] public string? Language { get; init; } /// /// Schema version of the RichGraph. /// [JsonPropertyName("schema")] public string Schema { get; init; } = "richgraph-v1"; } /// /// Information about the analyzer that computed the RichGraph. /// public sealed record RichGraphAnalyzerInfo { /// /// Name of the analyzer. /// [JsonPropertyName("name")] public required string Name { get; init; } /// /// Version of the analyzer. /// [JsonPropertyName("version")] public required string Version { get; init; } /// /// Configuration hash used for the analysis. /// [JsonPropertyName("config_hash")] public string? ConfigHash { get; init; } }