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
222 lines
5.9 KiB
C#
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;
|
|
}
|