using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using StellaOps.Policy.Determinization; using StellaOps.Policy.Determinization.Models; namespace StellaOps.Policy.Engine.Policies; /// /// Implements allow/quarantine/escalate logic per advisory specification. /// public sealed class DeterminizationPolicy : IDeterminizationPolicy { private readonly DeterminizationOptions _options; private readonly DeterminizationRuleSet _ruleSet; private readonly ILogger _logger; public DeterminizationPolicy( IOptions options, ILogger logger) { _options = options.Value; _ruleSet = DeterminizationRuleSet.Default(_options); _logger = logger; } public DeterminizationResult Evaluate(DeterminizationContext ctx) { ArgumentNullException.ThrowIfNull(ctx); // Get environment-specific thresholds var thresholds = GetEnvironmentThresholds(ctx.Environment); // Evaluate rules in priority order foreach (var rule in _ruleSet.Rules.OrderBy(r => r.Priority)) { if (rule.Condition(ctx, thresholds)) { var result = rule.Action(ctx, thresholds); result = result with { MatchedRule = rule.Name }; _logger.LogDebug( "Rule {RuleName} matched for CVE {CveId}: {Status}", rule.Name, ctx.SignalSnapshot.Cve, result.Status); return result; } } // Default: Deferred (no rule matched, needs more evidence) return DeterminizationResult.Deferred( "No determinization rule matched; additional evidence required"); } private EnvironmentThresholds GetEnvironmentThresholds(DeploymentEnvironment env) { return env switch { DeploymentEnvironment.Production => DefaultEnvironmentThresholds.Production, DeploymentEnvironment.Staging => DefaultEnvironmentThresholds.Staging, DeploymentEnvironment.Testing => DefaultEnvironmentThresholds.Development, DeploymentEnvironment.Development => DefaultEnvironmentThresholds.Development, _ => DefaultEnvironmentThresholds.Development }; } } /// /// Environment-specific thresholds for determinization decisions. /// public sealed record EnvironmentThresholds { public required DeploymentEnvironment Environment { get; init; } public required double MinConfidenceForNotAffected { get; init; } public required double MaxEntropyForAllow { get; init; } public required double EpssBlockThreshold { get; init; } public required bool RequireReachabilityForAllow { get; init; } } /// /// Default environment thresholds per advisory. /// public static class DefaultEnvironmentThresholds { public static EnvironmentThresholds Production => new() { Environment = DeploymentEnvironment.Production, MinConfidenceForNotAffected = 0.75, MaxEntropyForAllow = 0.3, EpssBlockThreshold = 0.3, RequireReachabilityForAllow = true }; public static EnvironmentThresholds Staging => new() { Environment = DeploymentEnvironment.Staging, MinConfidenceForNotAffected = 0.60, MaxEntropyForAllow = 0.5, EpssBlockThreshold = 0.4, RequireReachabilityForAllow = true }; public static EnvironmentThresholds Development => new() { Environment = DeploymentEnvironment.Development, MinConfidenceForNotAffected = 0.40, MaxEntropyForAllow = 0.7, EpssBlockThreshold = 0.6, RequireReachabilityForAllow = false }; }