// ----------------------------------------------------------------------------- // AttestationChain.cs // Sprint: SPRINT_3801_0001_0003_chain_verification (CHAIN-002) // Description: Models for attestation chain verification. // ----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Text.Json.Serialization; namespace StellaOps.Scanner.WebService.Contracts; /// /// Represents a chain of attestations for a finding. /// public sealed record AttestationChain { /// /// Content-addressed chain identifier. /// [JsonPropertyName("chain_id")] public required string ChainId { get; init; } /// /// The scan ID this chain belongs to. /// [JsonPropertyName("scan_id")] public required string ScanId { get; init; } /// /// The finding ID (e.g., CVE identifier) this chain is for. /// [JsonPropertyName("finding_id")] public required string FindingId { get; init; } /// /// The root digest (typically the scan/image digest). /// [JsonPropertyName("root_digest")] public required string RootDigest { get; init; } /// /// The attestations in this chain, ordered from root to leaf. /// [JsonPropertyName("attestations")] public required ImmutableList Attestations { get; init; } /// /// Whether the entire chain is verified. /// [JsonPropertyName("verified")] public required bool Verified { get; init; } /// /// When the chain was verified. /// [JsonPropertyName("verified_at")] public required DateTimeOffset VerifiedAt { get; init; } /// /// The chain status. /// [JsonPropertyName("chain_status")] public required ChainStatus Status { get; init; } /// /// When the earliest attestation in the chain expires. /// [JsonPropertyName("expires_at")] public DateTimeOffset? ExpiresAt { get; init; } } /// /// Represents a single attestation in the chain. /// public sealed record ChainAttestation { /// /// The type of attestation (e.g., "richgraph", "policy_decision", "human_approval"). /// [JsonPropertyName("type")] public required AttestationType Type { get; init; } /// /// The attestation ID. /// [JsonPropertyName("attestation_id")] public required string AttestationId { get; init; } /// /// When the attestation was created. /// [JsonPropertyName("created_at")] public required DateTimeOffset CreatedAt { get; init; } /// /// When the attestation expires. /// [JsonPropertyName("expires_at")] public required DateTimeOffset ExpiresAt { get; init; } /// /// Whether the attestation signature verified. /// [JsonPropertyName("verified")] public required bool Verified { get; init; } /// /// The verification status of this attestation. /// [JsonPropertyName("verification_status")] public required AttestationVerificationStatus VerificationStatus { get; init; } /// /// The subject digest this attestation covers. /// [JsonPropertyName("subject_digest")] public required string SubjectDigest { get; init; } /// /// The predicate type URI. /// [JsonPropertyName("predicate_type")] public required string PredicateType { get; init; } /// /// Optional error message if verification failed. /// [JsonPropertyName("error")] public string? Error { get; init; } } /// /// The type of attestation. /// [JsonConverter(typeof(JsonStringEnumConverter))] public enum AttestationType { /// /// RichGraph computation attestation. /// RichGraph, /// /// Policy decision attestation. /// PolicyDecision, /// /// Human approval attestation. /// HumanApproval, /// /// SBOM generation attestation. /// Sbom, /// /// Vulnerability scan attestation. /// VulnerabilityScan } /// /// The verification status of an attestation. /// [JsonConverter(typeof(JsonStringEnumConverter))] public enum AttestationVerificationStatus { /// /// Verification succeeded. /// Valid, /// /// Attestation has expired. /// Expired, /// /// Signature verification failed. /// InvalidSignature, /// /// Attestation not found. /// NotFound, /// /// Chain link broken (digest mismatch). /// ChainBroken, /// /// Attestation has been revoked. /// Revoked, /// /// Verification pending. /// Pending } /// /// The overall status of the attestation chain. /// [JsonConverter(typeof(JsonStringEnumConverter))] public enum ChainStatus { /// /// All attestations present and valid. /// Complete, /// /// Some attestations missing but core valid. /// Partial, /// /// One or more attestations past TTL. /// Expired, /// /// Signature verification failed. /// Invalid, /// /// Chain link missing or digest mismatch. /// Broken, /// /// Chain is empty (no attestations). /// Empty } /// /// Input for chain verification. /// public sealed record ChainVerificationInput { /// /// The scan ID to verify chain for. /// public required Domain.ScanId ScanId { get; init; } /// /// The finding ID to verify chain for. /// public required string FindingId { get; init; } /// /// The expected root digest. /// public required string RootDigest { get; init; } /// /// Optional: specific attestation types to verify. /// If null, verifies all available attestations. /// public IReadOnlyList? RequiredTypes { get; init; } /// /// Whether to require human approval in the chain. /// public bool RequireHumanApproval { get; init; } /// /// Grace period for expired attestations (default: 0). /// public TimeSpan ExpirationGracePeriod { get; init; } = TimeSpan.Zero; } /// /// Result of chain verification. /// public sealed record ChainVerificationResult { /// /// Whether verification succeeded. /// public required bool Success { get; init; } /// /// The verified chain. /// public AttestationChain? Chain { get; init; } /// /// Error message if verification failed. /// public string? Error { get; init; } /// /// Detailed verification results per attestation. /// public IReadOnlyList? Details { get; init; } /// /// Creates a successful result. /// public static ChainVerificationResult Succeeded( AttestationChain chain, IReadOnlyList? details = null) => new() { Success = true, Chain = chain, Details = details }; /// /// Creates a failed result. /// public static ChainVerificationResult Failed(string error, AttestationChain? chain = null) => new() { Success = false, Chain = chain, Error = error }; } /// /// Detailed verification result for a single attestation. /// public sealed record AttestationVerificationDetail { /// /// The attestation type. /// public required AttestationType Type { get; init; } /// /// The attestation ID. /// public required string AttestationId { get; init; } /// /// The verification status. /// public required AttestationVerificationStatus Status { get; init; } /// /// Whether the attestation was verified successfully. /// public required bool Verified { get; init; } /// /// Time taken for verification. /// public TimeSpan? VerificationTime { get; init; } /// /// Error message if verification failed. /// public string? Error { get; init; } }