This commit is contained in:
StellaOps Bot
2025-12-13 02:22:15 +02:00
parent 564df71bfb
commit 999e26a48e
395 changed files with 25045 additions and 2224 deletions

View File

@@ -231,6 +231,168 @@ public sealed class PolicyRuntimeEvaluationServiceTests
Assert.Equal("warn", response.Status);
}
[Fact]
public async Task EvaluateAsync_GatesUnreachableWithoutEvidenceRef_ToUnderInvestigation()
{
const string policy = """
policy "Reachability gate policy" syntax "stella-dsl@1" {
rule unreachable_to_not_affected priority 10 {
when reachability.state == "unreachable"
then status := "not_affected"
because "unreachable + evidence"
}
rule gated_to_under_investigation priority 20 {
when reachability.state == "under_investigation"
then status := "under_investigation"
because "unreachable but missing evidence"
}
rule default priority 100 {
when true
then status := "affected"
because "default"
}
}
""";
var harness = CreateHarness();
await harness.StoreTestPolicyAsync("pack-3", 1, policy);
var fact = new ReachabilityFact
{
Id = "fact-1",
TenantId = "tenant-1",
ComponentPurl = "pkg:npm/lodash@4.17.21",
AdvisoryId = "CVE-2024-0001",
State = ReachabilityState.Unreachable,
Confidence = 0.92m,
Score = 0m,
HasRuntimeEvidence = false,
Source = "graph-analyzer",
Method = AnalysisMethod.Static,
EvidenceRef = null,
EvidenceHash = "sha256:deadbeef",
ComputedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
Metadata = new Dictionary<string, object?>()
};
await harness.ReachabilityStore.SaveAsync(fact, CancellationToken.None);
var request = CreateRequest("pack-3", 1, severity: "Low");
var response = await harness.Service.EvaluateAsync(request, CancellationToken.None);
Assert.Equal("under_investigation", response.Status);
}
[Fact]
public async Task EvaluateAsync_GatesUnreachableWithLowConfidence_ToUnderInvestigation()
{
const string policy = """
policy "Reachability gate policy" syntax "stella-dsl@1" {
rule unreachable_to_not_affected priority 10 {
when reachability.state == "unreachable"
then status := "not_affected"
because "unreachable + evidence"
}
rule gated_to_under_investigation priority 20 {
when reachability.state == "under_investigation"
then status := "under_investigation"
because "unreachable but low confidence"
}
rule default priority 100 {
when true
then status := "affected"
because "default"
}
}
""";
var harness = CreateHarness();
await harness.StoreTestPolicyAsync("pack-4", 1, policy);
var fact = new ReachabilityFact
{
Id = "fact-1",
TenantId = "tenant-1",
ComponentPurl = "pkg:npm/lodash@4.17.21",
AdvisoryId = "CVE-2024-0001",
State = ReachabilityState.Unreachable,
Confidence = 0.7m,
Score = 0m,
HasRuntimeEvidence = false,
Source = "graph-analyzer",
Method = AnalysisMethod.Static,
EvidenceRef = "cas://reachability/facts/fact-1",
EvidenceHash = "sha256:deadbeef",
ComputedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
Metadata = new Dictionary<string, object?>()
};
await harness.ReachabilityStore.SaveAsync(fact, CancellationToken.None);
var request = CreateRequest("pack-4", 1, severity: "Low");
var response = await harness.Service.EvaluateAsync(request, CancellationToken.None);
Assert.Equal("under_investigation", response.Status);
}
[Fact]
public async Task EvaluateAsync_AllowsUnreachableWithEvidenceRefAndHighConfidence()
{
const string policy = """
policy "Reachability gate policy" syntax "stella-dsl@1" {
rule unreachable_to_not_affected priority 10 {
when reachability.state == "unreachable"
then status := "not_affected"
because "unreachable + evidence"
}
rule gated_to_under_investigation priority 20 {
when reachability.state == "under_investigation"
then status := "under_investigation"
because "gated"
}
rule default priority 100 {
when true
then status := "affected"
because "default"
}
}
""";
var harness = CreateHarness();
await harness.StoreTestPolicyAsync("pack-5", 1, policy);
var fact = new ReachabilityFact
{
Id = "fact-1",
TenantId = "tenant-1",
ComponentPurl = "pkg:npm/lodash@4.17.21",
AdvisoryId = "CVE-2024-0001",
State = ReachabilityState.Unreachable,
Confidence = 0.92m,
Score = 0m,
HasRuntimeEvidence = false,
Source = "graph-analyzer",
Method = AnalysisMethod.Static,
EvidenceRef = "cas://reachability/facts/fact-1",
EvidenceHash = "sha256:deadbeef",
ComputedAt = new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero),
Metadata = new Dictionary<string, object?>()
};
await harness.ReachabilityStore.SaveAsync(fact, CancellationToken.None);
var request = CreateRequest("pack-5", 1, severity: "Low");
var response = await harness.Service.EvaluateAsync(request, CancellationToken.None);
Assert.Equal("not_affected", response.Status);
}
private static RuntimeEvaluationRequest CreateRequest(
string packId,
int version,