warnings fixes, tests fixes, sprints completions

This commit is contained in:
Codex Assistant
2026-01-08 08:38:27 +02:00
parent 75611a505f
commit 0b5d786ddb
125 changed files with 14610 additions and 368 deletions

View File

@@ -1,3 +1,126 @@
using System.Collections.Immutable;
namespace StellaOps.Policy.Exceptions.Models;
public sealed record ExceptionApplication{public Guid Id{get;init;}public Guid TenantId{get;init;}public required string ExceptionId{get;init;}public required string FindingId{get;init;}public string? VulnerabilityId{get;init;}public required string OriginalStatus{get;init;}public required string AppliedStatus{get;init;}public required string EffectName{get;init;}public required string EffectType{get;init;}public Guid? EvaluationRunId{get;init;}public string? PolicyBundleDigest{get;init;}public DateTimeOffset AppliedAt{get;init;}public ImmutableDictionary<string,string> Metadata{get;init;}=ImmutableDictionary<string,string>.Empty;public static ExceptionApplication Create(Guid tenantId,string exceptionId,string findingId,string originalStatus,string appliedStatus,string effectName,string effectType,string? vulnerabilityId=null,Guid? evaluationRunId=null,string? policyBundleDigest=null,ImmutableDictionary<string,string>? metadata=null){ArgumentException.ThrowIfNullOrWhiteSpace(exceptionId);ArgumentException.ThrowIfNullOrWhiteSpace(findingId);return new ExceptionApplication{Id=Guid.NewGuid(),TenantId=tenantId,ExceptionId=exceptionId,FindingId=findingId,VulnerabilityId=vulnerabilityId,OriginalStatus=originalStatus,AppliedStatus=appliedStatus,EffectName=effectName,EffectType=effectType,EvaluationRunId=evaluationRunId,PolicyBundleDigest=policyBundleDigest,AppliedAt=DateTimeOffset.UtcNow,Metadata=metadata??ImmutableDictionary<string,string>.Empty};}}
/// <summary>
/// Represents an application of an exception to a specific finding.
/// </summary>
public sealed record ExceptionApplication
{
/// <summary>
/// Unique identifier for this application.
/// </summary>
public Guid Id { get; init; }
/// <summary>
/// Tenant identifier.
/// </summary>
public Guid TenantId { get; init; }
/// <summary>
/// The exception that was applied.
/// </summary>
public required string ExceptionId { get; init; }
/// <summary>
/// The finding this exception was applied to.
/// </summary>
public required string FindingId { get; init; }
/// <summary>
/// Optional vulnerability identifier.
/// </summary>
public string? VulnerabilityId { get; init; }
/// <summary>
/// The original status before the exception was applied.
/// </summary>
public required string OriginalStatus { get; init; }
/// <summary>
/// The status after the exception was applied.
/// </summary>
public required string AppliedStatus { get; init; }
/// <summary>
/// Name of the exception effect.
/// </summary>
public required string EffectName { get; init; }
/// <summary>
/// Type of the exception effect.
/// </summary>
public required string EffectType { get; init; }
/// <summary>
/// Optional evaluation run identifier.
/// </summary>
public Guid? EvaluationRunId { get; init; }
/// <summary>
/// Optional policy bundle digest.
/// </summary>
public string? PolicyBundleDigest { get; init; }
/// <summary>
/// Timestamp when the exception was applied.
/// </summary>
public DateTimeOffset AppliedAt { get; init; }
/// <summary>
/// Additional metadata.
/// </summary>
public ImmutableDictionary<string, string> Metadata { get; init; } = ImmutableDictionary<string, string>.Empty;
/// <summary>
/// Creates a new exception application with the specified parameters.
/// </summary>
/// <param name="tenantId">Tenant identifier.</param>
/// <param name="exceptionId">Exception identifier.</param>
/// <param name="findingId">Finding identifier.</param>
/// <param name="originalStatus">Original status before exception.</param>
/// <param name="appliedStatus">Status after exception.</param>
/// <param name="effectName">Name of the effect.</param>
/// <param name="effectType">Type of the effect.</param>
/// <param name="applicationId">Application ID for determinism. Required.</param>
/// <param name="appliedAt">Timestamp for determinism. Required.</param>
/// <param name="vulnerabilityId">Optional vulnerability ID.</param>
/// <param name="evaluationRunId">Optional evaluation run ID.</param>
/// <param name="policyBundleDigest">Optional policy bundle digest.</param>
/// <param name="metadata">Optional metadata.</param>
public static ExceptionApplication Create(
Guid tenantId,
string exceptionId,
string findingId,
string originalStatus,
string appliedStatus,
string effectName,
string effectType,
Guid applicationId,
DateTimeOffset appliedAt,
string? vulnerabilityId = null,
Guid? evaluationRunId = null,
string? policyBundleDigest = null,
ImmutableDictionary<string, string>? metadata = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(exceptionId);
ArgumentException.ThrowIfNullOrWhiteSpace(findingId);
return new ExceptionApplication
{
Id = applicationId,
TenantId = tenantId,
ExceptionId = exceptionId,
FindingId = findingId,
VulnerabilityId = vulnerabilityId,
OriginalStatus = originalStatus,
AppliedStatus = appliedStatus,
EffectName = effectName,
EffectType = effectType,
EvaluationRunId = evaluationRunId,
PolicyBundleDigest = policyBundleDigest,
AppliedAt = appliedAt,
Metadata = metadata ?? ImmutableDictionary<string, string>.Empty
};
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Immutable;
using StellaOps.Determinism.Abstractions;
namespace StellaOps.Policy.Exceptions.Models;
@@ -120,15 +121,17 @@ public sealed record ExceptionEvent
public static ExceptionEvent ForCreated(
string exceptionId,
string actorId,
TimeProvider timeProvider,
IGuidProvider guidProvider,
string? description = null,
string? clientInfo = null) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = 1,
EventType = ExceptionEventType.Created,
ActorId = actorId,
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = null,
NewStatus = ExceptionStatus.Proposed,
NewVersion = 1,
@@ -144,15 +147,17 @@ public sealed record ExceptionEvent
int sequenceNumber,
string actorId,
int newVersion,
TimeProvider timeProvider,
IGuidProvider guidProvider,
string? description = null,
string? clientInfo = null) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = sequenceNumber,
EventType = ExceptionEventType.Approved,
ActorId = actorId,
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = ExceptionStatus.Proposed,
NewStatus = ExceptionStatus.Approved,
NewVersion = newVersion,
@@ -169,15 +174,17 @@ public sealed record ExceptionEvent
string actorId,
int newVersion,
ExceptionStatus previousStatus,
TimeProvider timeProvider,
IGuidProvider guidProvider,
string? description = null,
string? clientInfo = null) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = sequenceNumber,
EventType = ExceptionEventType.Activated,
ActorId = actorId,
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = previousStatus,
NewStatus = ExceptionStatus.Active,
NewVersion = newVersion,
@@ -195,14 +202,16 @@ public sealed record ExceptionEvent
int newVersion,
ExceptionStatus previousStatus,
string reason,
TimeProvider timeProvider,
IGuidProvider guidProvider,
string? clientInfo = null) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = sequenceNumber,
EventType = ExceptionEventType.Revoked,
ActorId = actorId,
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = previousStatus,
NewStatus = ExceptionStatus.Revoked,
NewVersion = newVersion,
@@ -217,14 +226,16 @@ public sealed record ExceptionEvent
public static ExceptionEvent ForExpired(
string exceptionId,
int sequenceNumber,
int newVersion) => new()
int newVersion,
TimeProvider timeProvider,
IGuidProvider guidProvider) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = sequenceNumber,
EventType = ExceptionEventType.Expired,
ActorId = "system",
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = ExceptionStatus.Active,
NewStatus = ExceptionStatus.Expired,
NewVersion = newVersion,
@@ -241,15 +252,17 @@ public sealed record ExceptionEvent
int newVersion,
DateTimeOffset previousExpiry,
DateTimeOffset newExpiry,
TimeProvider timeProvider,
IGuidProvider guidProvider,
string? reason = null,
string? clientInfo = null) => new()
{
EventId = Guid.NewGuid(),
EventId = guidProvider.NewGuid(),
ExceptionId = exceptionId,
SequenceNumber = sequenceNumber,
EventType = ExceptionEventType.Extended,
ActorId = actorId,
OccurredAt = DateTimeOffset.UtcNow,
OccurredAt = timeProvider.GetUtcNow(),
PreviousStatus = ExceptionStatus.Active,
NewStatus = ExceptionStatus.Active,
NewVersion = newVersion,

View File

@@ -295,15 +295,19 @@ public sealed record ExceptionObject
LastRecheckResult.RecommendedAction == RecheckAction.RequireReapproval;
/// <summary>
/// Determines if this exception is currently effective.
/// Determines if this exception is currently effective at the given reference time.
/// </summary>
public bool IsEffective =>
/// <param name="referenceTime">The time to evaluate against.</param>
/// <returns>True if status is Active and not yet expired.</returns>
public bool IsEffectiveAt(DateTimeOffset referenceTime) =>
Status == ExceptionStatus.Active &&
DateTimeOffset.UtcNow < ExpiresAt;
referenceTime < ExpiresAt;
/// <summary>
/// Determines if this exception has expired.
/// Determines if this exception has expired at the given reference time.
/// </summary>
public bool HasExpired =>
DateTimeOffset.UtcNow >= ExpiresAt;
/// <param name="referenceTime">The time to evaluate against.</param>
/// <returns>True if the reference time is at or past the expiration.</returns>
public bool HasExpiredAt(DateTimeOffset referenceTime) =>
referenceTime >= ExpiresAt;
}