Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace StellaOps.Policy.Exceptions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Evidence hook requiring specific attestations before exception approval.
|
||||
/// </summary>
|
||||
public sealed record EvidenceHook
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this hook.
|
||||
/// </summary>
|
||||
public required string HookId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of evidence required.
|
||||
/// </summary>
|
||||
public required EvidenceType Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable description of the requirement.
|
||||
/// </summary>
|
||||
public required string Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this evidence is mandatory for approval.
|
||||
/// </summary>
|
||||
public bool IsMandatory { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Schema or predicate type for validation.
|
||||
/// </summary>
|
||||
public string? ValidationSchema { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum age of evidence (for freshness validation).
|
||||
/// </summary>
|
||||
public TimeSpan? MaxAge { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Required trust score for evidence source.
|
||||
/// </summary>
|
||||
public decimal? MinTrustScore { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of evidence that can be required.
|
||||
/// </summary>
|
||||
public enum EvidenceType
|
||||
{
|
||||
/// <summary>Feature flag is disabled in target environment.</summary>
|
||||
FeatureFlagDisabled,
|
||||
|
||||
/// <summary>Backport PR has been merged.</summary>
|
||||
BackportMerged,
|
||||
|
||||
/// <summary>Compensating control attestation.</summary>
|
||||
CompensatingControl,
|
||||
|
||||
/// <summary>Security review completed.</summary>
|
||||
SecurityReview,
|
||||
|
||||
/// <summary>Runtime mitigation in place.</summary>
|
||||
RuntimeMitigation,
|
||||
|
||||
/// <summary>WAF rule deployed.</summary>
|
||||
WAFRuleDeployed,
|
||||
|
||||
/// <summary>Custom attestation type.</summary>
|
||||
CustomAttestation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evidence submitted to satisfy a hook.
|
||||
/// </summary>
|
||||
public sealed record SubmittedEvidence
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this evidence submission.
|
||||
/// </summary>
|
||||
public required string EvidenceId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Hook this evidence satisfies.
|
||||
/// </summary>
|
||||
public required string HookId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Type of evidence.
|
||||
/// </summary>
|
||||
public required EvidenceType Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the evidence (URL, attestation ID, etc.).
|
||||
/// </summary>
|
||||
public required string Reference { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Evidence content or payload.
|
||||
/// </summary>
|
||||
public string? Content { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// DSSE envelope if signed.
|
||||
/// </summary>
|
||||
public string? DsseEnvelope { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether signature was verified.
|
||||
/// </summary>
|
||||
public bool SignatureVerified { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Trust score of evidence source.
|
||||
/// </summary>
|
||||
public decimal TrustScore { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When evidence was submitted.
|
||||
/// </summary>
|
||||
public required DateTimeOffset SubmittedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Who submitted the evidence.
|
||||
/// </summary>
|
||||
public required string SubmittedBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Validation status.
|
||||
/// </summary>
|
||||
public required EvidenceValidationStatus ValidationStatus { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Validation error if any.
|
||||
/// </summary>
|
||||
public string? ValidationError { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status of evidence validation.
|
||||
/// </summary>
|
||||
public enum EvidenceValidationStatus
|
||||
{
|
||||
Pending,
|
||||
Valid,
|
||||
Invalid,
|
||||
Expired,
|
||||
InsufficientTrust
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registry of required evidence hooks for an exception type.
|
||||
/// </summary>
|
||||
public sealed record EvidenceRequirements
|
||||
{
|
||||
/// <summary>
|
||||
/// Required evidence hooks.
|
||||
/// </summary>
|
||||
public required ImmutableArray<EvidenceHook> Hooks { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Evidence submitted so far.
|
||||
/// </summary>
|
||||
public ImmutableArray<SubmittedEvidence> SubmittedEvidence { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Whether all mandatory evidence is satisfied.
|
||||
/// </summary>
|
||||
public bool IsSatisfied => Hooks
|
||||
.Where(h => h.IsMandatory)
|
||||
.All(h => SubmittedEvidence.Any(e =>
|
||||
e.HookId == h.HookId &&
|
||||
e.ValidationStatus == EvidenceValidationStatus.Valid));
|
||||
|
||||
/// <summary>
|
||||
/// Missing mandatory evidence.
|
||||
/// </summary>
|
||||
public ImmutableArray<EvidenceHook> MissingEvidence => Hooks
|
||||
.Where(h => h.IsMandatory)
|
||||
.Where(h => !SubmittedEvidence.Any(e =>
|
||||
e.HookId == h.HookId &&
|
||||
e.ValidationStatus == EvidenceValidationStatus.Valid))
|
||||
.ToImmutableArray();
|
||||
}
|
||||
@@ -238,6 +238,11 @@ public sealed record ExceptionObject
|
||||
/// </summary>
|
||||
public ImmutableArray<string> EvidenceRefs { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Evidence requirements and submissions tied to this exception.
|
||||
/// </summary>
|
||||
public EvidenceRequirements? EvidenceRequirements { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Compensating controls in place that mitigate the risk.
|
||||
/// </summary>
|
||||
@@ -254,6 +259,41 @@ public sealed record ExceptionObject
|
||||
/// </summary>
|
||||
public string? TicketRef { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the applied recheck policy configuration.
|
||||
/// </summary>
|
||||
public string? RecheckPolicyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Recheck policy that governs automatic re-evaluation.
|
||||
/// If null, exception is only invalidated by expiry.
|
||||
/// </summary>
|
||||
public RecheckPolicy? RecheckPolicy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Result of last recheck evaluation.
|
||||
/// </summary>
|
||||
public RecheckEvaluationResult? LastRecheckResult { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When recheck was last evaluated.
|
||||
/// </summary>
|
||||
public DateTimeOffset? LastRecheckAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this exception is blocked by recheck policy.
|
||||
/// </summary>
|
||||
public bool IsBlockedByRecheck =>
|
||||
LastRecheckResult?.IsTriggered == true &&
|
||||
LastRecheckResult.RecommendedAction == RecheckAction.Block;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this exception requires re-approval.
|
||||
/// </summary>
|
||||
public bool RequiresReapproval =>
|
||||
LastRecheckResult?.IsTriggered == true &&
|
||||
LastRecheckResult.RecommendedAction == RecheckAction.RequireReapproval;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this exception is currently effective.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace StellaOps.Policy.Exceptions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Policy defining conditions that trigger exception re-evaluation.
|
||||
/// When any condition is met, the exception may be invalidated or flagged.
|
||||
/// </summary>
|
||||
public sealed record RecheckPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique identifier for this policy configuration.
|
||||
/// </summary>
|
||||
public required string PolicyId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable name for this policy.
|
||||
/// </summary>
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Conditions that trigger recheck.
|
||||
/// </summary>
|
||||
public required ImmutableArray<RecheckCondition> Conditions { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Default action when any condition is triggered.
|
||||
/// </summary>
|
||||
public required RecheckAction DefaultAction { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether this policy is active.
|
||||
/// </summary>
|
||||
public bool IsActive { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// When this policy was created.
|
||||
/// </summary>
|
||||
public required DateTimeOffset CreatedAt { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A single condition that triggers exception re-evaluation.
|
||||
/// </summary>
|
||||
public sealed record RecheckCondition
|
||||
{
|
||||
/// <summary>
|
||||
/// Type of condition to check.
|
||||
/// </summary>
|
||||
public required RecheckConditionType Type { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Threshold value (interpretation depends on Type).
|
||||
/// </summary>
|
||||
public decimal? Threshold { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Environment scopes where this condition applies.
|
||||
/// </summary>
|
||||
public ImmutableArray<string> EnvironmentScope { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Action to take when this specific condition is triggered.
|
||||
/// If null, uses policy's DefaultAction.
|
||||
/// </summary>
|
||||
public RecheckAction? Action { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable description of this condition.
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Types of recheck conditions.
|
||||
/// </summary>
|
||||
public enum RecheckConditionType
|
||||
{
|
||||
/// <summary>Reachability graph changes (new paths discovered).</summary>
|
||||
ReachGraphChange,
|
||||
|
||||
/// <summary>EPSS score exceeds threshold.</summary>
|
||||
EPSSAbove,
|
||||
|
||||
/// <summary>CVSS score exceeds threshold.</summary>
|
||||
CVSSAbove,
|
||||
|
||||
/// <summary>Unknown budget exceeds threshold.</summary>
|
||||
UnknownsAbove,
|
||||
|
||||
/// <summary>New CVE added to same package.</summary>
|
||||
NewCVEInPackage,
|
||||
|
||||
/// <summary>KEV (Known Exploited Vulnerability) flag set.</summary>
|
||||
KEVFlagged,
|
||||
|
||||
/// <summary>Exception nearing expiry (days before).</summary>
|
||||
ExpiryWithin,
|
||||
|
||||
/// <summary>VEX status changes (e.g., from NotAffected to Affected).</summary>
|
||||
VEXStatusChange,
|
||||
|
||||
/// <summary>Package version changes.</summary>
|
||||
PackageVersionChange
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Action to take when a recheck condition is triggered.
|
||||
/// </summary>
|
||||
public enum RecheckAction
|
||||
{
|
||||
/// <summary>Log warning but allow exception to remain active.</summary>
|
||||
Warn,
|
||||
|
||||
/// <summary>Require manual re-approval of exception.</summary>
|
||||
RequireReapproval,
|
||||
|
||||
/// <summary>Automatically revoke the exception.</summary>
|
||||
Revoke,
|
||||
|
||||
/// <summary>Block build/deployment pipeline.</summary>
|
||||
Block
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of evaluating recheck conditions against an exception.
|
||||
/// </summary>
|
||||
public sealed record RecheckEvaluationResult
|
||||
{
|
||||
/// <summary>Whether any conditions were triggered.</summary>
|
||||
public required bool IsTriggered { get; init; }
|
||||
|
||||
/// <summary>List of triggered conditions with details.</summary>
|
||||
public required ImmutableArray<TriggeredCondition> TriggeredConditions { get; init; }
|
||||
|
||||
/// <summary>Recommended action based on triggered conditions.</summary>
|
||||
public required RecheckAction? RecommendedAction { get; init; }
|
||||
|
||||
/// <summary>When this evaluation was performed.</summary>
|
||||
public required DateTimeOffset EvaluatedAt { get; init; }
|
||||
|
||||
/// <summary>Human-readable summary.</summary>
|
||||
public string Summary => IsTriggered
|
||||
? $"{TriggeredConditions.Length} condition(s) triggered: {string.Join(", ", TriggeredConditions.Select(t => t.Type))}"
|
||||
: "No conditions triggered";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Details of a triggered recheck condition.
|
||||
/// </summary>
|
||||
public sealed record TriggeredCondition(
|
||||
RecheckConditionType Type,
|
||||
string Description,
|
||||
decimal? CurrentValue,
|
||||
decimal? ThresholdValue,
|
||||
RecheckAction Action);
|
||||
Reference in New Issue
Block a user