save progress
This commit is contained in:
@@ -8,6 +8,7 @@ namespace StellaOps.Authority.Core.Tests.Verdicts;
|
||||
public sealed class InMemoryVerdictManifestStoreTests
|
||||
{
|
||||
private readonly InMemoryVerdictManifestStore _store = new();
|
||||
private static readonly DateTimeOffset BaseTime = DateTimeOffset.Parse("2025-01-01T00:00:00Z");
|
||||
|
||||
[Fact]
|
||||
public async Task StoreAndRetrieve_ByManifestId()
|
||||
@@ -59,7 +60,7 @@ public sealed class InMemoryVerdictManifestStoreTests
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
var manifest = CreateManifest($"m{i}", "t", policyHash: "p1", latticeVersion: "v1",
|
||||
evaluatedAt: DateTimeOffset.UtcNow.AddMinutes(-i));
|
||||
evaluatedAt: BaseTime.AddMinutes(-i));
|
||||
await _store.StoreAsync(manifest);
|
||||
}
|
||||
|
||||
@@ -137,7 +138,7 @@ public sealed class InMemoryVerdictManifestStoreTests
|
||||
VulnFeedSnapshotIds = ImmutableArray.Create("feed-1"),
|
||||
VexDocumentDigests = ImmutableArray.Create("sha256:vex"),
|
||||
ReachabilityGraphIds = ImmutableArray<string>.Empty,
|
||||
ClockCutoff = DateTimeOffset.UtcNow,
|
||||
ClockCutoff = BaseTime,
|
||||
},
|
||||
Result = new VerdictResult
|
||||
{
|
||||
@@ -148,7 +149,7 @@ public sealed class InMemoryVerdictManifestStoreTests
|
||||
},
|
||||
PolicyHash = policyHash,
|
||||
LatticeVersion = latticeVersion,
|
||||
EvaluatedAt = evaluatedAt ?? DateTimeOffset.UtcNow,
|
||||
EvaluatedAt = evaluatedAt ?? BaseTime,
|
||||
ManifestDigest = $"sha256:{manifestId}",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Authority.Core.Verdicts;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Authority.Core.Tests.Verdicts;
|
||||
|
||||
public sealed class NullVerdictManifestSignerTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task VerifyAsync_ReturnsInvalidWithDisabledReason()
|
||||
{
|
||||
var signer = new NullVerdictManifestSigner();
|
||||
var manifest = new VerdictManifest
|
||||
{
|
||||
ManifestId = "manifest-1",
|
||||
Tenant = "tenant-a",
|
||||
AssetDigest = "sha256:asset",
|
||||
VulnerabilityId = "CVE-2024-1234",
|
||||
Inputs = new VerdictInputs
|
||||
{
|
||||
SbomDigests = ImmutableArray.Create("sha256:sbom"),
|
||||
VulnFeedSnapshotIds = ImmutableArray.Create("feed-1"),
|
||||
VexDocumentDigests = ImmutableArray.Create("sha256:vex"),
|
||||
ReachabilityGraphIds = ImmutableArray<string>.Empty,
|
||||
ClockCutoff = DateTimeOffset.Parse("2025-01-01T00:00:00Z"),
|
||||
},
|
||||
Result = new VerdictResult
|
||||
{
|
||||
Status = VexStatus.NotAffected,
|
||||
Confidence = 0.5,
|
||||
Explanations = ImmutableArray<VerdictExplanation>.Empty,
|
||||
EvidenceRefs = ImmutableArray<string>.Empty,
|
||||
},
|
||||
PolicyHash = "sha256:policy",
|
||||
LatticeVersion = "1.0.0",
|
||||
EvaluatedAt = DateTimeOffset.Parse("2025-01-01T00:00:00Z"),
|
||||
ManifestDigest = "sha256:manifest",
|
||||
};
|
||||
|
||||
var result = await signer.VerifyAsync(manifest);
|
||||
|
||||
result.Valid.Should().BeFalse();
|
||||
result.Error.Should().Be("Signing disabled");
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Authority.Core.Verdicts;
|
||||
using Xunit;
|
||||
|
||||
@@ -10,7 +11,8 @@ public sealed class VerdictManifestBuilderTests
|
||||
[Fact]
|
||||
public void Build_CreatesValidManifest()
|
||||
{
|
||||
var builder = new VerdictManifestBuilder(() => "test-manifest-id")
|
||||
var clock = new FakeTimeProvider(DateTimeOffset.Parse("2025-01-01T12:00:00Z"));
|
||||
var builder = new VerdictManifestBuilder(() => "test-manifest-id", clock)
|
||||
.WithTenant("tenant-1")
|
||||
.WithAsset("sha256:abc123", "CVE-2024-1234")
|
||||
.WithInputs(
|
||||
@@ -59,7 +61,7 @@ public sealed class VerdictManifestBuilderTests
|
||||
|
||||
VerdictManifest BuildManifest(int seed)
|
||||
{
|
||||
return new VerdictManifestBuilder(() => "fixed-id")
|
||||
return new VerdictManifestBuilder(() => "fixed-id", TimeProvider.System)
|
||||
.WithTenant("tenant")
|
||||
.WithAsset("sha256:asset", "CVE-2024-0001")
|
||||
.WithInputs(
|
||||
@@ -104,7 +106,7 @@ public sealed class VerdictManifestBuilderTests
|
||||
{
|
||||
var clock = DateTimeOffset.Parse("2025-01-01T00:00:00Z");
|
||||
|
||||
var manifestA = new VerdictManifestBuilder(() => "id")
|
||||
var manifestA = new VerdictManifestBuilder(() => "id", TimeProvider.System)
|
||||
.WithTenant("t")
|
||||
.WithAsset("sha256:a", "CVE-1")
|
||||
.WithInputs(
|
||||
@@ -117,7 +119,7 @@ public sealed class VerdictManifestBuilderTests
|
||||
.WithClock(clock)
|
||||
.Build();
|
||||
|
||||
var manifestB = new VerdictManifestBuilder(() => "id")
|
||||
var manifestB = new VerdictManifestBuilder(() => "id", TimeProvider.System)
|
||||
.WithTenant("t")
|
||||
.WithAsset("sha256:a", "CVE-1")
|
||||
.WithInputs(
|
||||
@@ -148,14 +150,15 @@ public sealed class VerdictManifestBuilderTests
|
||||
[Fact]
|
||||
public void Build_NormalizesVulnerabilityIdToUpperCase()
|
||||
{
|
||||
var manifest = new VerdictManifestBuilder(() => "id")
|
||||
var clock = DateTimeOffset.Parse("2025-01-01T00:00:00Z");
|
||||
var manifest = new VerdictManifestBuilder(() => "id", TimeProvider.System)
|
||||
.WithTenant("t")
|
||||
.WithAsset("sha256:a", "cve-2024-1234")
|
||||
.WithInputs(
|
||||
sbomDigests: new[] { "sha256:s" },
|
||||
vulnFeedSnapshotIds: new[] { "f" },
|
||||
vexDocumentDigests: new[] { "v" },
|
||||
clockCutoff: DateTimeOffset.UtcNow)
|
||||
clockCutoff: clock)
|
||||
.WithResult(VexStatus.Affected, 0.5, Enumerable.Empty<VerdictExplanation>())
|
||||
.WithPolicy("p", "v")
|
||||
.Build();
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Authority.Core.Verdicts;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Authority.Core.Tests.Verdicts;
|
||||
|
||||
public sealed class VerdictReplayVerifierTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task VerifyAsync_ByManifestId_Throws()
|
||||
{
|
||||
var verifier = new VerdictReplayVerifier(new NullStore(), new NullVerdictManifestSigner(), new NullEvaluator());
|
||||
|
||||
var act = async () => await verifier.VerifyAsync("manifest-1", CancellationToken.None);
|
||||
|
||||
await act.Should().ThrowAsync<InvalidOperationException>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VerifyAsync_FailsWhenSignatureInvalid()
|
||||
{
|
||||
var verifier = new VerdictReplayVerifier(new NullStore(), new NullVerdictManifestSigner(), new NullEvaluator());
|
||||
var manifest = CreateManifest();
|
||||
|
||||
var result = await verifier.VerifyAsync(manifest, CancellationToken.None);
|
||||
|
||||
result.Success.Should().BeFalse();
|
||||
result.SignatureValid.Should().BeFalse();
|
||||
result.Error.Should().Contain("Signature verification failed");
|
||||
}
|
||||
|
||||
private static VerdictManifest CreateManifest()
|
||||
{
|
||||
return new VerdictManifest
|
||||
{
|
||||
ManifestId = "manifest-1",
|
||||
Tenant = "tenant-a",
|
||||
AssetDigest = "sha256:asset",
|
||||
VulnerabilityId = "CVE-2024-1234",
|
||||
Inputs = new VerdictInputs
|
||||
{
|
||||
SbomDigests = ImmutableArray.Create("sha256:sbom"),
|
||||
VulnFeedSnapshotIds = ImmutableArray.Create("feed-1"),
|
||||
VexDocumentDigests = ImmutableArray.Create("sha256:vex"),
|
||||
ReachabilityGraphIds = ImmutableArray<string>.Empty,
|
||||
ClockCutoff = DateTimeOffset.Parse("2025-01-01T00:00:00Z"),
|
||||
},
|
||||
Result = new VerdictResult
|
||||
{
|
||||
Status = VexStatus.NotAffected,
|
||||
Confidence = 0.5,
|
||||
Explanations = ImmutableArray<VerdictExplanation>.Empty,
|
||||
EvidenceRefs = ImmutableArray<string>.Empty,
|
||||
},
|
||||
PolicyHash = "sha256:policy",
|
||||
LatticeVersion = "1.0.0",
|
||||
EvaluatedAt = DateTimeOffset.Parse("2025-01-01T00:00:00Z"),
|
||||
ManifestDigest = "sha256:manifest",
|
||||
SignatureBase64 = "invalid"
|
||||
};
|
||||
}
|
||||
|
||||
private sealed class NullStore : IVerdictManifestStore
|
||||
{
|
||||
public Task<VerdictManifest> StoreAsync(VerdictManifest manifest, CancellationToken ct = default)
|
||||
=> Task.FromResult(manifest);
|
||||
|
||||
public Task<VerdictManifest?> GetByIdAsync(string tenant, string manifestId, CancellationToken ct = default)
|
||||
=> Task.FromResult<VerdictManifest?>(null);
|
||||
|
||||
public Task<VerdictManifest?> GetByScopeAsync(
|
||||
string tenant,
|
||||
string assetDigest,
|
||||
string vulnerabilityId,
|
||||
string? policyHash = null,
|
||||
string? latticeVersion = null,
|
||||
CancellationToken ct = default)
|
||||
=> Task.FromResult<VerdictManifest?>(null);
|
||||
|
||||
public Task<VerdictManifestPage> ListByPolicyAsync(
|
||||
string tenant,
|
||||
string policyHash,
|
||||
string latticeVersion,
|
||||
int limit = 100,
|
||||
string? pageToken = null,
|
||||
CancellationToken ct = default)
|
||||
=> Task.FromResult(new VerdictManifestPage { Manifests = ImmutableArray<VerdictManifest>.Empty });
|
||||
|
||||
public Task<VerdictManifestPage> ListByAssetAsync(
|
||||
string tenant,
|
||||
string assetDigest,
|
||||
int limit = 100,
|
||||
string? pageToken = null,
|
||||
CancellationToken ct = default)
|
||||
=> Task.FromResult(new VerdictManifestPage { Manifests = ImmutableArray<VerdictManifest>.Empty });
|
||||
|
||||
public Task<bool> DeleteAsync(string tenant, string manifestId, CancellationToken ct = default)
|
||||
=> Task.FromResult(false);
|
||||
}
|
||||
|
||||
private sealed class NullEvaluator : IVerdictEvaluator
|
||||
{
|
||||
public Task<VerdictResult> EvaluateAsync(
|
||||
string tenant,
|
||||
string assetDigest,
|
||||
string vulnerabilityId,
|
||||
VerdictInputs inputs,
|
||||
string policyHash,
|
||||
string latticeVersion,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
return Task.FromResult(new VerdictResult
|
||||
{
|
||||
Status = VexStatus.NotAffected,
|
||||
Confidence = 0.5,
|
||||
Explanations = ImmutableArray<VerdictExplanation>.Empty,
|
||||
EvidenceRefs = ImmutableArray<string>.Empty,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user