using System.Collections.Immutable; using System.Text.Json.Serialization; namespace StellaOps.Policy.Engine.WhatIfSimulation; /// /// Request for what-if simulation supporting hypothetical SBOM diffs and draft policies. /// public sealed record WhatIfSimulationRequest { /// /// Tenant identifier. /// [JsonPropertyName("tenant_id")] public required string TenantId { get; init; } /// /// Base snapshot ID to apply diffs to. /// [JsonPropertyName("base_snapshot_id")] public required string BaseSnapshotId { get; init; } /// /// Active policy pack ID to use as baseline. /// If DraftPolicy is provided, this will be compared against. /// [JsonPropertyName("baseline_pack_id")] public string? BaselinePackId { get; init; } /// /// Baseline policy version. If null, uses active version. /// [JsonPropertyName("baseline_pack_version")] public int? BaselinePackVersion { get; init; } /// /// Draft policy to simulate (not yet activated). /// If null, uses baseline policy. /// [JsonPropertyName("draft_policy")] public WhatIfDraftPolicy? DraftPolicy { get; init; } /// /// SBOM diffs to apply hypothetically. /// [JsonPropertyName("sbom_diffs")] public ImmutableArray SbomDiffs { get; init; } = ImmutableArray.Empty; /// /// Specific component PURLs to evaluate. If empty, evaluates affected by diffs. /// [JsonPropertyName("target_purls")] public ImmutableArray TargetPurls { get; init; } = ImmutableArray.Empty; /// /// Maximum number of components to evaluate. /// [JsonPropertyName("limit")] public int Limit { get; init; } = 1000; /// /// Whether to include detailed explanations for each decision. /// [JsonPropertyName("include_explanations")] public bool IncludeExplanations { get; init; } = false; /// /// Correlation ID for tracing. /// [JsonPropertyName("correlation_id")] public string? CorrelationId { get; init; } } /// /// Draft policy definition for simulation. /// public sealed record WhatIfDraftPolicy { /// /// Draft policy pack ID. /// [JsonPropertyName("pack_id")] public required string PackId { get; init; } /// /// Draft policy version. /// [JsonPropertyName("version")] public int Version { get; init; } /// /// Raw YAML policy definition to compile and evaluate. /// If provided, this is compiled on-the-fly. /// [JsonPropertyName("policy_yaml")] public string? PolicyYaml { get; init; } /// /// Pre-compiled bundle digest if available. /// [JsonPropertyName("bundle_digest")] public string? BundleDigest { get; init; } } /// /// Hypothetical SBOM modification for what-if simulation. /// public sealed record WhatIfSbomDiff { /// /// Type of modification: add, remove, upgrade, downgrade. /// [JsonPropertyName("operation")] public required string Operation { get; init; } /// /// Component PURL being modified. /// [JsonPropertyName("purl")] public required string Purl { get; init; } /// /// New version for upgrade/downgrade operations. /// [JsonPropertyName("new_version")] public string? NewVersion { get; init; } /// /// Original version (for reference in upgrades/downgrades). /// [JsonPropertyName("original_version")] public string? OriginalVersion { get; init; } /// /// Hypothetical advisory IDs affecting this component. /// [JsonPropertyName("advisory_ids")] public ImmutableArray AdvisoryIds { get; init; } = ImmutableArray.Empty; /// /// Hypothetical VEX status for this component. /// [JsonPropertyName("vex_status")] public string? VexStatus { get; init; } /// /// Hypothetical reachability state. /// [JsonPropertyName("reachability")] public string? Reachability { get; init; } } /// /// Response from what-if simulation. /// public sealed record WhatIfSimulationResponse { /// /// Simulation identifier. /// [JsonPropertyName("simulation_id")] public required string SimulationId { get; init; } /// /// Tenant identifier. /// [JsonPropertyName("tenant_id")] public required string TenantId { get; init; } /// /// Base snapshot ID used. /// [JsonPropertyName("base_snapshot_id")] public required string BaseSnapshotId { get; init; } /// /// Baseline policy used for comparison. /// [JsonPropertyName("baseline_policy")] public required WhatIfPolicyRef BaselinePolicy { get; init; } /// /// Simulated policy (draft or modified). /// [JsonPropertyName("simulated_policy")] public WhatIfPolicyRef? SimulatedPolicy { get; init; } /// /// Decision changes between baseline and simulation. /// [JsonPropertyName("decision_changes")] public required ImmutableArray DecisionChanges { get; init; } /// /// Summary of changes. /// [JsonPropertyName("summary")] public required WhatIfSummary Summary { get; init; } /// /// When the simulation was executed. /// [JsonPropertyName("executed_at")] public required DateTimeOffset ExecutedAt { get; init; } /// /// Execution duration in milliseconds. /// [JsonPropertyName("duration_ms")] public long DurationMs { get; init; } /// /// Correlation ID. /// [JsonPropertyName("correlation_id")] public string? CorrelationId { get; init; } } /// /// Policy reference in simulation. /// public sealed record WhatIfPolicyRef( [property: JsonPropertyName("pack_id")] string PackId, [property: JsonPropertyName("version")] int Version, [property: JsonPropertyName("bundle_digest")] string? BundleDigest, [property: JsonPropertyName("is_draft")] bool IsDraft); /// /// A decision change detected in what-if simulation. /// public sealed record WhatIfDecisionChange { /// /// Component PURL. /// [JsonPropertyName("purl")] public required string Purl { get; init; } /// /// Advisory ID if applicable. /// [JsonPropertyName("advisory_id")] public string? AdvisoryId { get; init; } /// /// Type of change: new, removed, status_changed, severity_changed. /// [JsonPropertyName("change_type")] public required string ChangeType { get; init; } /// /// Baseline decision. /// [JsonPropertyName("baseline")] public WhatIfDecision? Baseline { get; init; } /// /// Simulated decision. /// [JsonPropertyName("simulated")] public WhatIfDecision? Simulated { get; init; } /// /// SBOM diff that caused this change, if any. /// [JsonPropertyName("caused_by_diff")] public WhatIfSbomDiff? CausedByDiff { get; init; } /// /// Explanation for the change. /// [JsonPropertyName("explanation")] public WhatIfExplanation? Explanation { get; init; } } /// /// A decision in what-if simulation. /// public sealed record WhatIfDecision( [property: JsonPropertyName("status")] string Status, [property: JsonPropertyName("severity")] string? Severity, [property: JsonPropertyName("rule_name")] string? RuleName, [property: JsonPropertyName("priority")] int? Priority, [property: JsonPropertyName("exception_applied")] bool ExceptionApplied); /// /// Explanation for a what-if decision. /// public sealed record WhatIfExplanation { /// /// Rules that matched. /// [JsonPropertyName("matched_rules")] public ImmutableArray MatchedRules { get; init; } = ImmutableArray.Empty; /// /// Key factors in the decision. /// [JsonPropertyName("factors")] public ImmutableArray Factors { get; init; } = ImmutableArray.Empty; /// /// VEX evidence considered. /// [JsonPropertyName("vex_evidence")] public string? VexEvidence { get; init; } /// /// Reachability state. /// [JsonPropertyName("reachability")] public string? Reachability { get; init; } } /// /// Summary of what-if simulation results. /// public sealed record WhatIfSummary { /// /// Total components evaluated. /// [JsonPropertyName("total_evaluated")] public int TotalEvaluated { get; init; } /// /// Components with changed decisions. /// [JsonPropertyName("total_changed")] public int TotalChanged { get; init; } /// /// Components newly affected. /// [JsonPropertyName("newly_affected")] public int NewlyAffected { get; init; } /// /// Components no longer affected. /// [JsonPropertyName("no_longer_affected")] public int NoLongerAffected { get; init; } /// /// Status changes by type. /// [JsonPropertyName("status_changes")] public required ImmutableDictionary StatusChanges { get; init; } /// /// Severity changes by type (e.g., "low_to_high"). /// [JsonPropertyName("severity_changes")] public required ImmutableDictionary SeverityChanges { get; init; } /// /// Impact assessment. /// [JsonPropertyName("impact")] public required WhatIfImpact Impact { get; init; } } /// /// Impact assessment from what-if simulation. /// public sealed record WhatIfImpact( [property: JsonPropertyName("risk_delta")] string RiskDelta, // increased, decreased, unchanged [property: JsonPropertyName("blocked_count_delta")] int BlockedCountDelta, [property: JsonPropertyName("warning_count_delta")] int WarningCountDelta, [property: JsonPropertyName("recommendation")] string? Recommendation);