sprints and audit work
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// VexGatePolicyEvaluator.cs
|
||||
// Sprint: SPRINT_20260106_003_002_SCANNER_vex_gate_service
|
||||
// Description: Policy evaluator for VEX gate decisions.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace StellaOps.Scanner.Gate;
|
||||
|
||||
/// <summary>
|
||||
/// Default implementation of <see cref="IVexGatePolicy"/>.
|
||||
/// Evaluates evidence against policy rules in priority order.
|
||||
/// </summary>
|
||||
public sealed class VexGatePolicyEvaluator : IVexGatePolicy
|
||||
{
|
||||
private readonly ILogger<VexGatePolicyEvaluator> _logger;
|
||||
private readonly VexGatePolicy _policy;
|
||||
|
||||
public VexGatePolicyEvaluator(
|
||||
IOptions<VexGatePolicyOptions> options,
|
||||
ILogger<VexGatePolicyEvaluator> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_policy = options.Value.Policy ?? VexGatePolicy.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an evaluator with the default policy.
|
||||
/// </summary>
|
||||
public VexGatePolicyEvaluator(ILogger<VexGatePolicyEvaluator> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_policy = VexGatePolicy.Default;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public VexGatePolicy Policy => _policy;
|
||||
|
||||
/// <inheritdoc />
|
||||
public (VexGateDecision Decision, string RuleId, string Rationale) Evaluate(VexGateEvidence evidence)
|
||||
{
|
||||
// Sort rules by priority descending and evaluate in order
|
||||
var sortedRules = _policy.Rules
|
||||
.OrderByDescending(r => r.Priority)
|
||||
.ToList();
|
||||
|
||||
foreach (var rule in sortedRules)
|
||||
{
|
||||
if (rule.Condition.Matches(evidence))
|
||||
{
|
||||
var rationale = BuildRationale(rule, evidence);
|
||||
|
||||
_logger.LogDebug(
|
||||
"VEX gate rule matched: {RuleId} -> {Decision} for evidence with vendor status {VendorStatus}",
|
||||
rule.RuleId,
|
||||
rule.Decision,
|
||||
evidence.VendorStatus);
|
||||
|
||||
return (rule.Decision, rule.RuleId, rationale);
|
||||
}
|
||||
}
|
||||
|
||||
// No rule matched, return default
|
||||
var defaultRationale = "No policy rule matched; applying default decision";
|
||||
|
||||
_logger.LogDebug(
|
||||
"No VEX gate rule matched; defaulting to {Decision}",
|
||||
_policy.DefaultDecision);
|
||||
|
||||
return (_policy.DefaultDecision, "default", defaultRationale);
|
||||
}
|
||||
|
||||
private static string BuildRationale(VexGatePolicyRule rule, VexGateEvidence evidence)
|
||||
{
|
||||
return rule.RuleId switch
|
||||
{
|
||||
"block-exploitable-reachable" =>
|
||||
"Exploitable + reachable, no compensating control",
|
||||
|
||||
"warn-high-not-reachable" =>
|
||||
string.Format(
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
"{0} severity but not reachable from entrypoints",
|
||||
evidence.SeverityLevel ?? "High"),
|
||||
|
||||
"pass-vendor-not-affected" =>
|
||||
"Vendor VEX statement declares not_affected",
|
||||
|
||||
"pass-backport-confirmed" =>
|
||||
"Vendor VEX statement confirms fixed via backport",
|
||||
|
||||
_ => string.Format(
|
||||
System.Globalization.CultureInfo.InvariantCulture,
|
||||
"Policy rule '{0}' matched",
|
||||
rule.RuleId)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Options for VEX gate policy configuration.
|
||||
/// </summary>
|
||||
public sealed class VexGatePolicyOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom policy to use instead of default.
|
||||
/// </summary>
|
||||
public VexGatePolicy? Policy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the gate is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = true;
|
||||
}
|
||||
Reference in New Issue
Block a user