// -----------------------------------------------------------------------------
// 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; }
}