using System.Text.Json.Serialization;
namespace StellaOps.Findings.Ledger.Domain;
///
/// Immutable decision event per advisory ยง11.
///
public sealed class DecisionEvent
{
///
/// Unique identifier for this decision event.
///
public string Id { get; init; } = Guid.NewGuid().ToString("N");
///
/// Alert identifier.
///
public required string AlertId { get; init; }
///
/// Artifact identifier (image digest/commit hash).
///
public required string ArtifactId { get; init; }
///
/// Actor who made the decision.
///
public required string ActorId { get; init; }
///
/// When the decision was recorded (UTC).
///
public required DateTimeOffset Timestamp { get; init; }
///
/// Decision status: affected, not_affected, under_investigation.
///
public required string DecisionStatus { get; init; }
///
/// Preset reason code.
///
public required string ReasonCode { get; init; }
///
/// Custom reason text.
///
public string? ReasonText { get; init; }
///
/// Content-addressed evidence hashes.
///
public required List EvidenceHashes { get; init; }
///
/// Policy context (ruleset version, policy id).
///
public string? PolicyContext { get; init; }
///
/// Deterministic replay token for reproducibility.
///
public required string ReplayToken { get; init; }
}
///
/// Alert entity for triage.
///
public sealed class Alert
{
///
/// Unique alert identifier.
///
public required string AlertId { get; init; }
///
/// Tenant identifier.
///
public required string TenantId { get; init; }
///
/// Artifact identifier (image digest/commit hash).
///
public required string ArtifactId { get; init; }
///
/// Vulnerability identifier.
///
public required string VulnId { get; init; }
///
/// Affected component PURL.
///
public string? ComponentPurl { get; init; }
///
/// Severity level (critical, high, medium, low).
///
public required string Severity { get; init; }
///
/// Triage band (hot, warm, cold).
///
public required string Band { get; init; }
///
/// Alert status (open, in_review, decided, closed).
///
public required string Status { get; init; }
///
/// Composite triage score.
///
public double Score { get; init; }
///
/// When the alert was created.
///
public required DateTimeOffset CreatedAt { get; init; }
///
/// When the alert was last updated.
///
public DateTimeOffset? UpdatedAt { get; init; }
///
/// Number of decisions recorded for this alert.
///
public int DecisionCount { get; init; }
}
///
/// Evidence bundle for an alert.
///
public sealed class EvidenceBundle
{
///
/// Alert identifier.
///
public required string AlertId { get; init; }
///
/// Reachability evidence.
///
public EvidenceSection? Reachability { get; init; }
///
/// Call stack evidence.
///
public EvidenceSection? CallStack { get; init; }
///
/// Provenance evidence.
///
public EvidenceSection? Provenance { get; init; }
///
/// VEX status evidence.
///
public VexStatusEvidence? VexStatus { get; init; }
///
/// Content-addressed hashes for all evidence.
///
public required EvidenceHashes Hashes { get; init; }
///
/// When the bundle was computed.
///
public required DateTimeOffset ComputedAt { get; init; }
}
///
/// Evidence section with status and proof.
///
public sealed class EvidenceSection
{
///
/// Status: available, loading, unavailable, error.
///
public required string Status { get; init; }
///
/// Content hash for this evidence.
///
public string? Hash { get; init; }
///
/// Proof data (type-specific).
///
public object? Proof { get; init; }
}
///
/// VEX status evidence with history.
///
public sealed class VexStatusEvidence
{
///
/// Status: available, unavailable.
///
public required string Status { get; init; }
///
/// Current VEX statement.
///
public VexStatement? Current { get; init; }
///
/// Historical VEX statements.
///
public IReadOnlyList? History { get; init; }
}
///
/// VEX statement summary.
///
public sealed class VexStatement
{
///
/// Statement identifier.
///
public required string StatementId { get; init; }
///
/// VEX status.
///
public required string Status { get; init; }
///
/// Justification code.
///
public string? Justification { get; init; }
///
/// Impact statement.
///
public string? ImpactStatement { get; init; }
///
/// When the statement was issued.
///
public required DateTimeOffset Timestamp { get; init; }
///
/// Statement issuer.
///
public string? Issuer { get; init; }
}
///
/// Content-addressed hashes for evidence bundle.
///
public sealed class EvidenceHashes
{
///
/// All hashes for the bundle.
///
public required IReadOnlyList Hashes { get; init; }
}
///
/// Audit timeline for an alert.
///
public sealed class AuditTimeline
{
///
/// Alert identifier.
///
public required string AlertId { get; init; }
///
/// List of audit events.
///
public required IReadOnlyList Events { get; init; }
///
/// Total count of events.
///
public int TotalCount { get; init; }
}
///
/// Single audit event.
///
public sealed class AuditEvent
{
///
/// Event identifier.
///
public required string EventId { get; init; }
///
/// Type of audit event.
///
public required string EventType { get; init; }
///
/// Actor who triggered the event.
///
public required string ActorId { get; init; }
///
/// When the event occurred.
///
public required DateTimeOffset Timestamp { get; init; }
///
/// Event-specific details.
///
public object? Details { get; init; }
///
/// Replay token if applicable.
///
public string? ReplayToken { get; init; }
}
///
/// Alert diff result.
///
public sealed class AlertDiff
{
///
/// Alert identifier.
///
public required string AlertId { get; init; }
///
/// Baseline scan identifier.
///
public string? BaselineScanId { get; init; }
///
/// Current scan identifier.
///
public required string CurrentScanId { get; init; }
///
/// SBOM diff summary.
///
public SbomDiff? SbomDiff { get; init; }
///
/// VEX diff summary.
///
public VexDiff? VexDiff { get; init; }
///
/// When the diff was computed.
///
public required DateTimeOffset ComputedAt { get; init; }
}
///
/// SBOM diff summary.
///
public sealed class SbomDiff
{
///
/// Number of added components.
///
public int AddedComponents { get; init; }
///
/// Number of removed components.
///
public int RemovedComponents { get; init; }
///
/// Number of changed components.
///
public int ChangedComponents { get; init; }
///
/// Detailed changes.
///
public IReadOnlyList? Changes { get; init; }
}
///
/// Single component diff.
///
public sealed class ComponentDiff
{
///
/// Component PURL.
///
public required string Purl { get; init; }
///
/// Type of change: added, removed, changed.
///
public required string ChangeType { get; init; }
///
/// Old version if changed/removed.
///
public string? OldVersion { get; init; }
///
/// New version if changed/added.
///
public string? NewVersion { get; init; }
}
///
/// VEX diff summary.
///
public sealed class VexDiff
{
///
/// Number of status changes.
///
public int StatusChanges { get; init; }
///
/// Number of new statements.
///
public int NewStatements { get; init; }
///
/// Detailed changes.
///
public IReadOnlyList? Changes { get; init; }
}
///
/// Single VEX status diff.
///
public sealed class VexStatusDiff
{
///
/// Vulnerability identifier.
///
public required string VulnId { get; init; }
///
/// Old status.
///
public string? OldStatus { get; init; }
///
/// New status.
///
public required string NewStatus { get; init; }
///
/// When the change occurred.
///
public required DateTimeOffset Timestamp { get; init; }
}