Files
git.stella-ops.org/src/Policy/StellaOps.Policy.Engine/Policies/DeterminizationPolicy.cs
2026-01-07 09:43:12 +02:00

113 lines
3.8 KiB
C#

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StellaOps.Policy.Determinization;
using StellaOps.Policy.Determinization.Models;
namespace StellaOps.Policy.Engine.Policies;
/// <summary>
/// Implements allow/quarantine/escalate logic per advisory specification.
/// </summary>
public sealed class DeterminizationPolicy : IDeterminizationPolicy
{
private readonly DeterminizationOptions _options;
private readonly DeterminizationRuleSet _ruleSet;
private readonly ILogger<DeterminizationPolicy> _logger;
public DeterminizationPolicy(
IOptions<DeterminizationOptions> options,
ILogger<DeterminizationPolicy> 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
};
}
}
/// <summary>
/// Environment-specific thresholds for determinization decisions.
/// </summary>
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; }
}
/// <summary>
/// Default environment thresholds per advisory.
/// </summary>
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
};
}