Files
git.stella-ops.org/src/Policy/StellaOps.Policy.Engine/EffectiveDecisionMap/EffectiveDecisionModels.cs
StellaOps Bot 05da719048
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
up
2025-11-28 09:41:08 +02:00

222 lines
5.9 KiB
C#

using System.Collections.Immutable;
using System.Text.Json.Serialization;
namespace StellaOps.Policy.Engine.EffectiveDecisionMap;
/// <summary>
/// Represents an effective policy decision for an asset/snapshot.
/// Stored in Redis for Graph overlay lookups.
/// </summary>
public sealed record EffectiveDecisionEntry
{
/// <summary>
/// Tenant identifier.
/// </summary>
[JsonPropertyName("tenant_id")]
public required string TenantId { get; init; }
/// <summary>
/// Asset identifier (PURL or SBOM ID).
/// </summary>
[JsonPropertyName("asset_id")]
public required string AssetId { get; init; }
/// <summary>
/// Snapshot identifier (SBOM version or evaluation run).
/// </summary>
[JsonPropertyName("snapshot_id")]
public required string SnapshotId { get; init; }
/// <summary>
/// Policy pack ID that produced this decision.
/// </summary>
[JsonPropertyName("pack_id")]
public required string PackId { get; init; }
/// <summary>
/// Policy pack version.
/// </summary>
[JsonPropertyName("pack_version")]
public required int PackVersion { get; init; }
/// <summary>
/// Final decision status (allow, warn, deny, blocked).
/// </summary>
[JsonPropertyName("status")]
public required string Status { get; init; }
/// <summary>
/// Severity level if applicable.
/// </summary>
[JsonPropertyName("severity")]
public string? Severity { get; init; }
/// <summary>
/// Rule name that determined the decision.
/// </summary>
[JsonPropertyName("rule_name")]
public string? RuleName { get; init; }
/// <summary>
/// Priority of the applied rule.
/// </summary>
[JsonPropertyName("priority")]
public int? Priority { get; init; }
/// <summary>
/// Exception ID if an exception was applied.
/// </summary>
[JsonPropertyName("exception_id")]
public string? ExceptionId { get; init; }
/// <summary>
/// Count of advisories affecting this asset.
/// </summary>
[JsonPropertyName("advisory_count")]
public int AdvisoryCount { get; init; }
/// <summary>
/// Count of critical/high severity findings.
/// </summary>
[JsonPropertyName("high_severity_count")]
public int HighSeverityCount { get; init; }
/// <summary>
/// Aggregated annotations from the decision.
/// </summary>
[JsonPropertyName("annotations")]
public ImmutableDictionary<string, string> Annotations { get; init; } = ImmutableDictionary<string, string>.Empty;
/// <summary>
/// Version counter for cache coherency.
/// </summary>
[JsonPropertyName("version")]
public required long Version { get; init; }
/// <summary>
/// When this entry was evaluated.
/// </summary>
[JsonPropertyName("evaluated_at")]
public required DateTimeOffset EvaluatedAt { get; init; }
/// <summary>
/// When this entry expires.
/// </summary>
[JsonPropertyName("expires_at")]
public required DateTimeOffset ExpiresAt { get; init; }
/// <summary>
/// Correlation ID for tracing.
/// </summary>
[JsonPropertyName("correlation_id")]
public string? CorrelationId { get; init; }
}
/// <summary>
/// Result of an effective decision map query.
/// </summary>
public sealed record EffectiveDecisionQueryResult
{
/// <summary>
/// Found entries mapped by asset ID.
/// </summary>
public required IReadOnlyDictionary<string, EffectiveDecisionEntry> Entries { get; init; }
/// <summary>
/// Asset IDs that were not found.
/// </summary>
public required IReadOnlyList<string> NotFound { get; init; }
/// <summary>
/// Current version of the decision map.
/// </summary>
public long MapVersion { get; init; }
/// <summary>
/// Whether the result came from cache.
/// </summary>
public bool FromCache { get; init; }
}
/// <summary>
/// Summary statistics for a snapshot's effective decisions.
/// </summary>
public sealed record EffectiveDecisionSummary
{
/// <summary>
/// Snapshot ID.
/// </summary>
public required string SnapshotId { get; init; }
/// <summary>
/// Total assets evaluated.
/// </summary>
public int TotalAssets { get; init; }
/// <summary>
/// Count by status.
/// </summary>
public required IReadOnlyDictionary<string, int> StatusCounts { get; init; }
/// <summary>
/// Count by severity.
/// </summary>
public required IReadOnlyDictionary<string, int> SeverityCounts { get; init; }
/// <summary>
/// Assets with exceptions applied.
/// </summary>
public int ExceptionCount { get; init; }
/// <summary>
/// Map version at time of summary.
/// </summary>
public long MapVersion { get; init; }
/// <summary>
/// When this summary was computed.
/// </summary>
public DateTimeOffset ComputedAt { get; init; }
}
/// <summary>
/// Filter options for querying effective decisions.
/// </summary>
public sealed record EffectiveDecisionFilter
{
/// <summary>
/// Filter by status values.
/// </summary>
public IReadOnlyList<string>? Statuses { get; init; }
/// <summary>
/// Filter by severity values.
/// </summary>
public IReadOnlyList<string>? Severities { get; init; }
/// <summary>
/// Include only assets with exceptions.
/// </summary>
public bool? HasException { get; init; }
/// <summary>
/// Filter by minimum advisory count.
/// </summary>
public int? MinAdvisoryCount { get; init; }
/// <summary>
/// Filter by minimum high severity count.
/// </summary>
public int? MinHighSeverityCount { get; init; }
/// <summary>
/// Maximum results to return.
/// </summary>
public int Limit { get; init; } = 1000;
/// <summary>
/// Offset for pagination.
/// </summary>
public int Offset { get; init; } = 0;
}