up
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
using Xunit;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.Policy.Engine.Domain;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.PolicyDsl;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Tests;
|
||||
|
||||
@@ -21,7 +22,7 @@ public sealed class PolicyBundleServiceTests
|
||||
public async Task CompileAndStoreAsync_SucceedsAndStoresBundle()
|
||||
{
|
||||
var services = CreateServices();
|
||||
var request = new PolicyBundleRequest(new PolicyDslPayload("stella-dsl@1", BaselineDsl), signingKeyId: "test-key");
|
||||
var request = new PolicyBundleRequest(new PolicyDslPayload("stella-dsl@1", BaselineDsl), SigningKeyId: "test-key");
|
||||
|
||||
var response = await services.BundleService.CompileAndStoreAsync("pack-1", 1, request, CancellationToken.None);
|
||||
|
||||
@@ -35,7 +36,7 @@ public sealed class PolicyBundleServiceTests
|
||||
public async Task CompileAndStoreAsync_FailsWithBadSyntax()
|
||||
{
|
||||
var services = CreateServices();
|
||||
var request = new PolicyBundleRequest(new PolicyDslPayload("unknown", "policy bad"), signingKeyId: null);
|
||||
var request = new PolicyBundleRequest(new PolicyDslPayload("unknown", "policy bad"), SigningKeyId: null);
|
||||
|
||||
var response = await services.BundleService.CompileAndStoreAsync("pack-1", 1, request, CancellationToken.None);
|
||||
|
||||
@@ -48,7 +49,7 @@ public sealed class PolicyBundleServiceTests
|
||||
{
|
||||
var compiler = new PolicyCompiler();
|
||||
var complexity = new PolicyComplexityAnalyzer();
|
||||
var options = Options.Create(new PolicyEngineOptions());
|
||||
var options = Microsoft.Extensions.Options.Options.Create(new PolicyEngineOptions());
|
||||
var compilationService = new PolicyCompilationService(compiler, complexity, new StaticOptionsMonitor(options.Value), TimeProvider.System);
|
||||
var repo = new InMemoryPolicyPackRepository();
|
||||
return new ServiceHarness(
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy;
|
||||
using StellaOps.PolicyDsl;
|
||||
using StellaOps.Policy.Engine.Compilation;
|
||||
using StellaOps.Policy.Engine.Options;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.PolicyDsl;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Tests;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
using Xunit;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Policy.Engine.Domain;
|
||||
using StellaOps.Policy.Engine.Ledger;
|
||||
using StellaOps.Policy.Engine.Orchestration;
|
||||
using StellaOps.Policy.Engine.Services;
|
||||
using StellaOps.Policy.Engine.Snapshots;
|
||||
using StellaOps.Policy.Engine.TrustWeighting;
|
||||
using StellaOps.Policy.Engine.Violations;
|
||||
|
||||
namespace StellaOps.Policy.Engine.Tests;
|
||||
|
||||
public sealed class PolicyDecisionServiceTests
|
||||
{
|
||||
private static (PolicyDecisionService service, string snapshotId) BuildService()
|
||||
{
|
||||
var clock = new FakeTimeProvider(DateTimeOffset.Parse("2025-11-27T10:00:00Z"));
|
||||
|
||||
var jobStore = new InMemoryOrchestratorJobStore();
|
||||
var resultStore = new InMemoryWorkerResultStore(jobStore);
|
||||
var exportStore = new InMemoryLedgerExportStore();
|
||||
var ledger = new LedgerExportService(clock, jobStore, resultStore, exportStore);
|
||||
var snapshotStore = new InMemorySnapshotStore();
|
||||
var violationStore = new InMemoryViolationEventStore();
|
||||
var trust = new TrustWeightingService(clock);
|
||||
|
||||
var snapshotService = new SnapshotService(clock, ledger, snapshotStore);
|
||||
var eventService = new ViolationEventService(snapshotStore, jobStore, violationStore);
|
||||
var fusionService = new SeverityFusionService(violationStore, trust);
|
||||
var conflictService = new ConflictHandlingService(violationStore);
|
||||
var evidenceService = new EvidenceSummaryService(clock);
|
||||
|
||||
var decisionService = new PolicyDecisionService(
|
||||
eventService,
|
||||
fusionService,
|
||||
conflictService,
|
||||
evidenceService);
|
||||
|
||||
// Setup test data
|
||||
var job = new OrchestratorJob(
|
||||
JobId: "job-decision-test",
|
||||
TenantId: "acme",
|
||||
ContextId: "ctx",
|
||||
PolicyProfileHash: "hash",
|
||||
RequestedAt: clock.GetUtcNow(),
|
||||
Priority: "normal",
|
||||
BatchItems: new[]
|
||||
{
|
||||
new OrchestratorJobItem("pkg:npm/lodash@4.17.21", "CVE-2021-23337"),
|
||||
new OrchestratorJobItem("pkg:npm/axios@0.21.1", "CVE-2021-3749"),
|
||||
new OrchestratorJobItem("pkg:maven/log4j@2.14.1", "CVE-2021-44228")
|
||||
},
|
||||
Callbacks: null,
|
||||
TraceRef: "trace-decision",
|
||||
Status: "completed",
|
||||
DeterminismHash: "hash",
|
||||
CompletedAt: clock.GetUtcNow(),
|
||||
ResultHash: "res");
|
||||
|
||||
jobStore.SaveAsync(job).GetAwaiter().GetResult();
|
||||
|
||||
resultStore.SaveAsync(new WorkerRunResult(
|
||||
job.JobId,
|
||||
"worker-decision",
|
||||
clock.GetUtcNow(),
|
||||
clock.GetUtcNow(),
|
||||
new[]
|
||||
{
|
||||
new WorkerResultItem("pkg:npm/lodash@4.17.21", "CVE-2021-23337", "violation", "trace-lodash"),
|
||||
new WorkerResultItem("pkg:npm/axios@0.21.1", "CVE-2021-3749", "warn", "trace-axios"),
|
||||
new WorkerResultItem("pkg:maven/log4j@2.14.1", "CVE-2021-44228", "violation", "trace-log4j")
|
||||
},
|
||||
"hash")).GetAwaiter().GetResult();
|
||||
|
||||
ledger.BuildAsync(new LedgerExportRequest("acme")).GetAwaiter().GetResult();
|
||||
var snapshot = snapshotService.CreateAsync(new SnapshotRequest("acme", "overlay-decision")).GetAwaiter().GetResult();
|
||||
|
||||
return (decisionService, snapshot.SnapshotId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_ReturnsDecisionsWithEvidence()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(snapshotId);
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.Equal(snapshotId, response.SnapshotId);
|
||||
Assert.Equal(3, response.Decisions.Count);
|
||||
Assert.All(response.Decisions, d =>
|
||||
{
|
||||
Assert.False(string.IsNullOrWhiteSpace(d.SeverityFused));
|
||||
Assert.NotNull(d.Evidence);
|
||||
Assert.NotNull(d.TopSources);
|
||||
Assert.True(d.TopSources.Count > 0);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_BuildsSummaryStatistics()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(snapshotId);
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.Equal(3, response.Summary.TotalDecisions);
|
||||
Assert.NotEmpty(response.Summary.SeverityCounts);
|
||||
Assert.NotEmpty(response.Summary.TopSeveritySources);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_FiltersById()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(
|
||||
SnapshotId: snapshotId,
|
||||
AdvisoryId: "CVE-2021-44228");
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.Single(response.Decisions);
|
||||
Assert.Equal("CVE-2021-44228", response.Decisions[0].AdvisoryId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_FiltersByTenant()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(
|
||||
SnapshotId: snapshotId,
|
||||
TenantId: "acme");
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.All(response.Decisions, d => Assert.Equal("acme", d.TenantId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_LimitsTopSources()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(
|
||||
SnapshotId: snapshotId,
|
||||
MaxSources: 1);
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.All(response.Decisions, d =>
|
||||
{
|
||||
Assert.True(d.TopSources.Count <= 1);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_ExcludesEvidenceWhenNotRequested()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(
|
||||
SnapshotId: snapshotId,
|
||||
IncludeEvidence: false);
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.All(response.Decisions, d => Assert.Null(d.Evidence));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_ReturnsDeterministicOrder()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(snapshotId);
|
||||
|
||||
var response1 = await service.GetDecisionsAsync(request);
|
||||
var response2 = await service.GetDecisionsAsync(request);
|
||||
|
||||
Assert.Equal(
|
||||
response1.Decisions.Select(d => d.ComponentPurl),
|
||||
response2.Decisions.Select(d => d.ComponentPurl));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_ThrowsOnEmptySnapshotId()
|
||||
{
|
||||
var (service, _) = BuildService();
|
||||
var request = new PolicyDecisionRequest(string.Empty);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(() => service.GetDecisionsAsync(request));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetDecisionsAsync_TopSourcesHaveRanks()
|
||||
{
|
||||
var (service, snapshotId) = BuildService();
|
||||
var request = new PolicyDecisionRequest(snapshotId);
|
||||
|
||||
var response = await service.GetDecisionsAsync(request);
|
||||
|
||||
foreach (var decision in response.Decisions)
|
||||
{
|
||||
for (var i = 0; i < decision.TopSources.Count; i++)
|
||||
{
|
||||
Assert.Equal(i + 1, decision.TopSources[i].Rank);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="9.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
Reference in New Issue
Block a user