save progress

This commit is contained in:
StellaOps Bot
2026-01-02 21:06:27 +02:00
parent f46bde5575
commit 3f197814c5
441 changed files with 21545 additions and 4306 deletions

View File

@@ -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}",
};
}

View File

@@ -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");
}
}

View File

@@ -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();

View File

@@ -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,
});
}
}
}