198 lines
6.0 KiB
C#
198 lines
6.0 KiB
C#
namespace StellaOps.Policy.Explainability;
|
|
|
|
/// <summary>
|
|
/// Structured verdict rationale following the 4-line template.
|
|
/// Line 1: Evidence summary
|
|
/// Line 2: Policy clause that triggered the decision
|
|
/// Line 3: Attestations and proofs supporting the verdict
|
|
/// Line 4: Final decision with score and recommendation
|
|
/// </summary>
|
|
public sealed record VerdictRationale
|
|
{
|
|
/// <summary>Schema version for forward compatibility.</summary>
|
|
[JsonPropertyName("schema_version")]
|
|
public string SchemaVersion { get; init; } = "1.0";
|
|
|
|
/// <summary>Unique rationale ID (content-addressed).</summary>
|
|
[JsonPropertyName("rationale_id")]
|
|
public required string RationaleId { get; init; }
|
|
|
|
/// <summary>Reference to the verdict being explained.</summary>
|
|
[JsonPropertyName("verdict_ref")]
|
|
public required VerdictReference VerdictRef { get; init; }
|
|
|
|
/// <summary>Line 1: Evidence summary.</summary>
|
|
[JsonPropertyName("evidence")]
|
|
public required RationaleEvidence Evidence { get; init; }
|
|
|
|
/// <summary>Line 2: Policy clause that triggered the decision.</summary>
|
|
[JsonPropertyName("policy_clause")]
|
|
public required RationalePolicyClause PolicyClause { get; init; }
|
|
|
|
/// <summary>Line 3: Attestations and proofs supporting the verdict.</summary>
|
|
[JsonPropertyName("attestations")]
|
|
public required RationaleAttestations Attestations { get; init; }
|
|
|
|
/// <summary>Line 4: Final decision with score and recommendation.</summary>
|
|
[JsonPropertyName("decision")]
|
|
public required RationaleDecision Decision { get; init; }
|
|
|
|
/// <summary>Generation timestamp (UTC).</summary>
|
|
[JsonPropertyName("generated_at")]
|
|
public required DateTimeOffset GeneratedAt { get; init; }
|
|
|
|
/// <summary>Input digests for reproducibility.</summary>
|
|
[JsonPropertyName("input_digests")]
|
|
public required RationaleInputDigests InputDigests { get; init; }
|
|
}
|
|
|
|
/// <summary>Reference to the verdict being explained.</summary>
|
|
public sealed record VerdictReference
|
|
{
|
|
[JsonPropertyName("attestation_id")]
|
|
public required string AttestationId { get; init; }
|
|
|
|
[JsonPropertyName("artifact_digest")]
|
|
public required string ArtifactDigest { get; init; }
|
|
|
|
[JsonPropertyName("policy_id")]
|
|
public required string PolicyId { get; init; }
|
|
|
|
[JsonPropertyName("cve")]
|
|
public string? Cve { get; init; }
|
|
|
|
[JsonPropertyName("component_purl")]
|
|
public string? ComponentPurl { get; init; }
|
|
}
|
|
|
|
/// <summary>Line 1: Evidence summary.</summary>
|
|
public sealed record RationaleEvidence
|
|
{
|
|
[JsonPropertyName("cve")]
|
|
public required string Cve { get; init; }
|
|
|
|
[JsonPropertyName("component")]
|
|
public required ComponentIdentity Component { get; init; }
|
|
|
|
[JsonPropertyName("reachability")]
|
|
public ReachabilityDetail? Reachability { get; init; }
|
|
|
|
[JsonPropertyName("formatted_text")]
|
|
public required string FormattedText { get; init; }
|
|
}
|
|
|
|
public sealed record ComponentIdentity
|
|
{
|
|
[JsonPropertyName("purl")]
|
|
public required string Purl { get; init; }
|
|
|
|
[JsonPropertyName("name")]
|
|
public string? Name { get; init; }
|
|
|
|
[JsonPropertyName("version")]
|
|
public string? Version { get; init; }
|
|
|
|
[JsonPropertyName("ecosystem")]
|
|
public string? Ecosystem { get; init; }
|
|
}
|
|
|
|
public sealed record ReachabilityDetail
|
|
{
|
|
[JsonPropertyName("vulnerable_function")]
|
|
public string? VulnerableFunction { get; init; }
|
|
|
|
[JsonPropertyName("entry_point")]
|
|
public string? EntryPoint { get; init; }
|
|
|
|
[JsonPropertyName("path_summary")]
|
|
public string? PathSummary { get; init; }
|
|
}
|
|
|
|
/// <summary>Line 2: Policy clause reference.</summary>
|
|
public sealed record RationalePolicyClause
|
|
{
|
|
[JsonPropertyName("clause_id")]
|
|
public required string ClauseId { get; init; }
|
|
|
|
[JsonPropertyName("rule_description")]
|
|
public required string RuleDescription { get; init; }
|
|
|
|
[JsonPropertyName("conditions")]
|
|
public required IReadOnlyList<string> Conditions { get; init; }
|
|
|
|
[JsonPropertyName("formatted_text")]
|
|
public required string FormattedText { get; init; }
|
|
}
|
|
|
|
/// <summary>Line 3: Attestations and proofs.</summary>
|
|
public sealed record RationaleAttestations
|
|
{
|
|
[JsonPropertyName("path_witness")]
|
|
public AttestationReference? PathWitness { get; init; }
|
|
|
|
[JsonPropertyName("vex_statements")]
|
|
public IReadOnlyList<AttestationReference>? VexStatements { get; init; }
|
|
|
|
[JsonPropertyName("provenance")]
|
|
public AttestationReference? Provenance { get; init; }
|
|
|
|
[JsonPropertyName("formatted_text")]
|
|
public required string FormattedText { get; init; }
|
|
}
|
|
|
|
public sealed record AttestationReference
|
|
{
|
|
[JsonPropertyName("id")]
|
|
public required string Id { get; init; }
|
|
|
|
[JsonPropertyName("type")]
|
|
public required string Type { get; init; }
|
|
|
|
[JsonPropertyName("digest")]
|
|
public string? Digest { get; init; }
|
|
|
|
[JsonPropertyName("summary")]
|
|
public string? Summary { get; init; }
|
|
}
|
|
|
|
/// <summary>Line 4: Final decision.</summary>
|
|
public sealed record RationaleDecision
|
|
{
|
|
[JsonPropertyName("verdict")]
|
|
public required string Verdict { get; init; }
|
|
|
|
[JsonPropertyName("score")]
|
|
public double? Score { get; init; }
|
|
|
|
[JsonPropertyName("recommendation")]
|
|
public required string Recommendation { get; init; }
|
|
|
|
[JsonPropertyName("mitigation")]
|
|
public MitigationGuidance? Mitigation { get; init; }
|
|
|
|
[JsonPropertyName("formatted_text")]
|
|
public required string FormattedText { get; init; }
|
|
}
|
|
|
|
public sealed record MitigationGuidance
|
|
{
|
|
[JsonPropertyName("action")]
|
|
public required string Action { get; init; }
|
|
|
|
[JsonPropertyName("details")]
|
|
public string? Details { get; init; }
|
|
}
|
|
|
|
/// <summary>Input digests for reproducibility.</summary>
|
|
public sealed record RationaleInputDigests
|
|
{
|
|
[JsonPropertyName("verdict_digest")]
|
|
public required string VerdictDigest { get; init; }
|
|
|
|
[JsonPropertyName("policy_digest")]
|
|
public string? PolicyDigest { get; init; }
|
|
|
|
[JsonPropertyName("evidence_digest")]
|
|
public string? EvidenceDigest { get; init; }
|
|
}
|