// ============================================================================= // IAttestationParser.cs // Attestation parsing abstraction for DSSE/in-toto attestations // Part of Step 2: Evidence Collection (Task T6) // ============================================================================= namespace StellaOps.AirGap.Importer.Reconciliation.Parsers; /// /// Interface for parsing DSSE-wrapped in-toto attestations. /// public interface IAttestationParser { /// /// Parses a DSSE envelope from the given file path. /// /// Path to the attestation file. /// Cancellation token. /// Parsed attestation result. Task ParseAsync(string filePath, CancellationToken cancellationToken = default); /// /// Parses a DSSE envelope from a stream. /// /// Stream containing the attestation content. /// Cancellation token. /// Parsed attestation result. Task ParseAsync(Stream stream, CancellationToken cancellationToken = default); /// /// Detects if a file is a DSSE attestation. /// /// Path to the file. /// True if the file appears to be a DSSE attestation. bool IsAttestation(string filePath); } /// /// Result of parsing an attestation document. /// public sealed record AttestationParseResult { /// /// Whether parsing was successful. /// public bool IsSuccess { get; init; } /// /// Error message if parsing failed. /// public string? ErrorMessage { get; init; } /// /// The parsed DSSE envelope. /// public DsseEnvelope? Envelope { get; init; } /// /// The parsed in-toto statement (payload). /// public InTotoStatement? Statement { get; init; } /// /// Creates a successful parse result. /// public static AttestationParseResult Success(DsseEnvelope envelope, InTotoStatement statement) { return new AttestationParseResult { IsSuccess = true, Envelope = envelope, Statement = statement }; } /// /// Creates a failed parse result. /// public static AttestationParseResult Failure(string errorMessage) { return new AttestationParseResult { IsSuccess = false, ErrorMessage = errorMessage }; } } /// /// Represents a DSSE (Dead Simple Signing Envelope). /// public sealed record DsseEnvelope { /// /// Payload type (typically "application/vnd.in-toto+json"). /// public required string PayloadType { get; init; } /// /// Base64-encoded payload. /// public required string Payload { get; init; } /// /// Signatures on the envelope. /// public IReadOnlyList Signatures { get; init; } = []; } /// /// Represents a signature in a DSSE envelope. /// public sealed record DsseSignature { /// /// Key identifier (e.g., key ID or certificate fingerprint). /// public string? KeyId { get; init; } /// /// Base64-encoded signature. /// public required string Sig { get; init; } /// /// Certificate chain (if present). /// public string? Cert { get; init; } } /// /// Represents an in-toto statement (attestation payload). /// public sealed record InTotoStatement { /// /// Statement type (typically "https://in-toto.io/Statement/v1"). /// public required string Type { get; init; } /// /// Predicate type URI (e.g., "https://slsa.dev/provenance/v1"). /// public required string PredicateType { get; init; } /// /// Subjects (artifacts) this statement applies to. /// public IReadOnlyList Subjects { get; init; } = []; /// /// Raw predicate JSON for further processing. /// public string? PredicateJson { get; init; } } /// /// Represents a subject in an in-toto statement. /// public sealed record InTotoSubject { /// /// Subject name (typically a file path or artifact reference). /// public string? Name { get; init; } /// /// Subject digests (algorithm -> hash). /// public IReadOnlyDictionary Digest { get; init; } = new Dictionary(); /// /// Gets the normalized SHA-256 digest if available. /// public string? GetSha256Digest() { if (Digest.TryGetValue("sha256", out var hash)) { return "sha256:" + hash.ToLowerInvariant(); } return null; } } /// /// Well-known predicate types for attestations. /// public static class PredicateTypes { public const string SlsaProvenanceV1 = "https://slsa.dev/provenance/v1"; public const string SlsaProvenanceV02 = "https://slsa.dev/provenance/v0.2"; public const string InTotoLink = "https://in-toto.io/Link/v1"; public const string Spdx = "https://spdx.dev/Document"; public const string CycloneDx = "https://cyclonedx.org/bom"; public const string OpenVex = "https://openvex.dev/ns/v0.2.0"; public const string Csaf = "https://docs.oasis-open.org/csaf/csaf/v2.0"; public const string ScorecardV2 = "https://ossf.github.io/scorecard/v2"; public const string VulnerabilityReport = "https://cosign.sigstore.dev/attestation/vuln/v1"; }