Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
95 lines
3.7 KiB
C#
95 lines
3.7 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Time.Testing;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Policy.Tests;
|
|
|
|
public sealed class PolicySnapshotStoreTests
|
|
{
|
|
private const string BasePolicyYaml = """
|
|
version: "1.0"
|
|
rules:
|
|
- name: Block Critical
|
|
severity: [Critical]
|
|
action: block
|
|
""";
|
|
|
|
[Fact]
|
|
public async Task SaveAsync_CreatesNewSnapshotAndAuditEntry()
|
|
{
|
|
var snapshotRepo = new InMemoryPolicySnapshotRepository();
|
|
var auditRepo = new InMemoryPolicyAuditRepository();
|
|
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 10, 18, 10, 0, 0, TimeSpan.Zero));
|
|
var store = new PolicySnapshotStore(snapshotRepo, auditRepo, timeProvider, NullLogger<PolicySnapshotStore>.Instance);
|
|
|
|
var content = new PolicySnapshotContent(BasePolicyYaml, PolicyDocumentFormat.Yaml, "cli", "test", null);
|
|
|
|
var result = await store.SaveAsync(content, CancellationToken.None);
|
|
|
|
Assert.True(result.Success);
|
|
Assert.True(result.Created);
|
|
Assert.NotNull(result.Snapshot);
|
|
Assert.Equal("rev-1", result.Snapshot!.RevisionId);
|
|
Assert.Equal(result.Digest, result.Snapshot.Digest);
|
|
Assert.Equal(timeProvider.GetUtcNow(), result.Snapshot.CreatedAt);
|
|
Assert.Equal(PolicyScoringConfig.Default.Version, result.Snapshot.ScoringConfig.Version);
|
|
|
|
var latest = await store.GetLatestAsync();
|
|
Assert.Equal(result.Snapshot, latest);
|
|
|
|
var audits = await auditRepo.ListAsync(10);
|
|
Assert.Single(audits);
|
|
Assert.Equal(result.Digest, audits[0].Digest);
|
|
Assert.Equal("snapshot.created", audits[0].Action);
|
|
Assert.Equal("rev-1", audits[0].RevisionId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveAsync_DoesNotCreateNewRevisionWhenDigestUnchanged()
|
|
{
|
|
var snapshotRepo = new InMemoryPolicySnapshotRepository();
|
|
var auditRepo = new InMemoryPolicyAuditRepository();
|
|
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2025, 10, 18, 10, 0, 0, TimeSpan.Zero));
|
|
var store = new PolicySnapshotStore(snapshotRepo, auditRepo, timeProvider, NullLogger<PolicySnapshotStore>.Instance);
|
|
|
|
var content = new PolicySnapshotContent(BasePolicyYaml, PolicyDocumentFormat.Yaml, "cli", "test", null);
|
|
var first = await store.SaveAsync(content, CancellationToken.None);
|
|
Assert.True(first.Created);
|
|
|
|
timeProvider.Advance(TimeSpan.FromHours(1));
|
|
var second = await store.SaveAsync(content, CancellationToken.None);
|
|
|
|
Assert.True(second.Success);
|
|
Assert.False(second.Created);
|
|
Assert.Equal(first.Digest, second.Digest);
|
|
Assert.Equal("rev-1", second.Snapshot!.RevisionId);
|
|
Assert.Equal(PolicyScoringConfig.Default.Version, second.Snapshot.ScoringConfig.Version);
|
|
|
|
var audits = await auditRepo.ListAsync(10);
|
|
Assert.Single(audits);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveAsync_ReturnsFailureWhenValidationFails()
|
|
{
|
|
var snapshotRepo = new InMemoryPolicySnapshotRepository();
|
|
var auditRepo = new InMemoryPolicyAuditRepository();
|
|
var store = new PolicySnapshotStore(snapshotRepo, auditRepo, TimeProvider.System, NullLogger<PolicySnapshotStore>.Instance);
|
|
|
|
const string invalidYaml = "version: '1.0'\nrules: []";
|
|
var content = new PolicySnapshotContent(invalidYaml, PolicyDocumentFormat.Yaml, null, null, null);
|
|
|
|
var result = await store.SaveAsync(content, CancellationToken.None);
|
|
|
|
Assert.False(result.Success);
|
|
Assert.False(result.Created);
|
|
Assert.Null(result.Snapshot);
|
|
|
|
var audits = await auditRepo.ListAsync(5);
|
|
Assert.Empty(audits);
|
|
}
|
|
}
|