using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using StellaOps.Policy; using StellaOps.Policy.Determinization; using StellaOps.Policy.Determinization.Models; using StellaOps.Policy.Engine.Policies; namespace StellaOps.Policy.Engine.Tests.Policies; public class DeterminizationPolicyTests { private readonly DeterminizationPolicy _policy; public DeterminizationPolicyTests() { var options = Options.Create(new DeterminizationOptions()); _policy = new DeterminizationPolicy(options, NullLogger.Instance); } [Fact] public void Evaluate_RuntimeEvidenceLoaded_ReturnsEscalated() { // Arrange var context = CreateContext( runtime: new SignalState { HasValue = true, Value = new RuntimeEvidence { ObservedLoaded = true } }); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Escalated); result.MatchedRule.Should().Be("RuntimeEscalation"); result.Reason.Should().Contain("Runtime evidence shows vulnerable code loaded"); } [Fact] public void Evaluate_HighEpss_ReturnsQuarantined() { // Arrange var context = CreateContext( epss: new SignalState { HasValue = true, Value = new EpssEvidence { Score = 0.8 } }, environment: DeploymentEnvironment.Production); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Blocked); result.MatchedRule.Should().Be("EpssQuarantine"); result.Reason.Should().Contain("EPSS score"); } [Fact] public void Evaluate_ReachableCode_ReturnsQuarantined() { // Arrange var context = CreateContext( reachability: new SignalState { HasValue = true, Value = new ReachabilityEvidence { IsReachable = true, Confidence = 0.9 } }); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Blocked); result.MatchedRule.Should().Be("ReachabilityQuarantine"); result.Reason.Should().Contain("reachable"); } [Fact] public void Evaluate_HighEntropyInProduction_ReturnsQuarantined() { // Arrange var context = CreateContext( entropy: 0.5, environment: DeploymentEnvironment.Production); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Blocked); result.MatchedRule.Should().Be("ProductionEntropyBlock"); result.Reason.Should().Contain("High uncertainty"); } [Fact] public void Evaluate_StaleEvidence_ReturnsDeferred() { // Arrange var context = CreateContext( isStale: true); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Deferred); result.MatchedRule.Should().Be("StaleEvidenceDefer"); result.Reason.Should().Contain("stale"); } [Fact] public void Evaluate_ModerateUncertaintyInDev_ReturnsGuardedPass() { // Arrange var context = CreateContext( entropy: 0.5, trustScore: 0.3, environment: DeploymentEnvironment.Development); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.GuardedPass); result.MatchedRule.Should().Be("GuardedAllowNonProd"); result.GuardRails.Should().NotBeNull(); result.GuardRails!.EnableMonitoring.Should().BeTrue(); } [Fact] public void Evaluate_UnreachableWithHighConfidence_ReturnsAllowed() { // Arrange var context = CreateContext( reachability: new SignalState { HasValue = true, Value = new ReachabilityEvidence { IsReachable = false, Confidence = 0.9 } }, trustScore: 0.8); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Pass); result.MatchedRule.Should().Be("UnreachableAllow"); result.Reason.Should().Contain("unreachable"); } [Fact] public void Evaluate_VexNotAffected_ReturnsAllowed() { // Arrange var context = CreateContext( vex: new SignalState { HasValue = true, Value = new VexClaimSummary { IsNotAffected = true, IssuerTrust = 0.9 } }, trustScore: 0.8); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Pass); result.MatchedRule.Should().Be("VexNotAffectedAllow"); result.Reason.Should().Contain("not_affected"); } [Fact] public void Evaluate_SufficientEvidenceLowEntropy_ReturnsAllowed() { // Arrange var context = CreateContext( entropy: 0.2, trustScore: 0.8, environment: DeploymentEnvironment.Production); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Pass); result.MatchedRule.Should().Be("SufficientEvidenceAllow"); result.Reason.Should().Contain("Sufficient evidence"); } [Fact] public void Evaluate_ModerateUncertaintyTier_ReturnsGuardedPass() { // Arrange var context = CreateContext( tier: UncertaintyTier.Moderate, trustScore: 0.5, entropy: 0.5); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.GuardedPass); result.MatchedRule.Should().Be("GuardedAllowModerateUncertainty"); result.GuardRails.Should().NotBeNull(); } [Fact] public void Evaluate_NoMatchingRule_ReturnsDeferred() { // Arrange var context = CreateContext( entropy: 0.9, trustScore: 0.1, environment: DeploymentEnvironment.Production); // Act var result = _policy.Evaluate(context); // Assert result.Status.Should().Be(PolicyVerdictStatus.Deferred); result.MatchedRule.Should().Be("DefaultDefer"); result.Reason.Should().Contain("Insufficient evidence"); } private static DeterminizationContext CreateContext( SignalState? epss = null, SignalState? vex = null, SignalState? reachability = null, SignalState? runtime = null, double entropy = 0.0, double trustScore = 0.0, UncertaintyTier tier = UncertaintyTier.Minimal, DeploymentEnvironment environment = DeploymentEnvironment.Development, bool isStale = false) { var snapshot = new SignalSnapshot { Cve = "CVE-2024-0001", Purl = "pkg:npm/test@1.0.0", Epss = epss ?? SignalState.NotQueried(), Vex = vex ?? SignalState.NotQueried(), Reachability = reachability ?? SignalState.NotQueried(), Runtime = runtime ?? SignalState.NotQueried(), Backport = SignalState.NotQueried(), Sbom = SignalState.NotQueried(), Cvss = SignalState.NotQueried(), SnapshotAt = DateTimeOffset.UtcNow }; return new DeterminizationContext { SignalSnapshot = snapshot, UncertaintyScore = new UncertaintyScore { Entropy = entropy, Tier = tier, Completeness = 1.0 - entropy, MissingSignals = [] }, Decay = new ObservationDecay { LastSignalUpdate = DateTimeOffset.UtcNow.AddDays(-1), AgeDays = 1, DecayedMultiplier = isStale ? 0.3 : 0.9, IsStale = isStale }, TrustScore = trustScore, Environment = environment }; } }