100 lines
3.7 KiB
C#
100 lines
3.7 KiB
C#
using StellaOps.PacksRegistry.Core.Services;
|
|
using StellaOps.PacksRegistry.Infrastructure.InMemory;
|
|
using StellaOps.PacksRegistry.Infrastructure.Verification;
|
|
|
|
using StellaOps.TestKit;
|
|
namespace StellaOps.PacksRegistry.Tests;
|
|
|
|
public sealed class PackServiceTests
|
|
{
|
|
private static byte[] SampleContent => System.Text.Encoding.UTF8.GetBytes("sample-pack-content");
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task Upload_persists_pack_with_digest()
|
|
{
|
|
var ct = CancellationToken.None;
|
|
var repo = new InMemoryPackRepository();
|
|
var verifier = new SimpleSignatureVerifier();
|
|
var service = new PackService(repo, verifier, new InMemoryAuditRepository(), null, TimeProvider.System);
|
|
|
|
var record = await service.UploadAsync(
|
|
name: "demo-pack",
|
|
version: "1.0.0",
|
|
tenantId: "tenant-1",
|
|
content: SampleContent,
|
|
signature: null,
|
|
provenanceUri: "https://example/manifest.json",
|
|
provenanceContent: null,
|
|
metadata: new Dictionary<string, string> { ["lang"] = "csharp" },
|
|
cancellationToken: ct);
|
|
|
|
Assert.Equal("demo-pack@1.0.0", record.PackId);
|
|
Assert.NotNull(record.Digest);
|
|
|
|
var listed = await service.ListAsync("tenant-1", ct);
|
|
Assert.Single(listed);
|
|
Assert.Equal(record.PackId, listed[0].PackId);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task Upload_rejects_when_digest_mismatch()
|
|
{
|
|
var ct = CancellationToken.None;
|
|
var repo = new InMemoryPackRepository();
|
|
var verifier = new AlwaysFailSignatureVerifier();
|
|
var service = new PackService(repo, verifier, new InMemoryAuditRepository(), null, TimeProvider.System);
|
|
|
|
await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
|
service.UploadAsync(
|
|
name: "demo-pack",
|
|
version: "1.0.0",
|
|
tenantId: "tenant-1",
|
|
content: SampleContent,
|
|
signature: "bogus",
|
|
provenanceUri: null,
|
|
provenanceContent: null,
|
|
metadata: null,
|
|
cancellationToken: ct));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public async Task Rotate_signature_updates_record_and_audits()
|
|
{
|
|
var ct = CancellationToken.None;
|
|
var repo = new InMemoryPackRepository();
|
|
var audit = new InMemoryAuditRepository();
|
|
var verifier = new SimpleSignatureVerifier();
|
|
var service = new PackService(repo, verifier, audit, null, TimeProvider.System);
|
|
|
|
var record = await service.UploadAsync(
|
|
name: "demo-pack",
|
|
version: "1.0.0",
|
|
tenantId: "tenant-1",
|
|
content: SampleContent,
|
|
signature: null,
|
|
provenanceUri: null,
|
|
provenanceContent: null,
|
|
metadata: null,
|
|
cancellationToken: ct);
|
|
|
|
var digest = record.Digest;
|
|
var newSignature = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(digest));
|
|
|
|
var rotated = await service.RotateSignatureAsync(record.PackId, record.TenantId, newSignature, cancellationToken: ct);
|
|
|
|
Assert.Equal(newSignature, rotated.Signature);
|
|
|
|
var auditEvents = await audit.ListAsync(record.TenantId, ct);
|
|
Assert.Contains(auditEvents, a => a.Event == "signature.rotated" && a.PackId == record.PackId);
|
|
}
|
|
|
|
private sealed class AlwaysFailSignatureVerifier : StellaOps.PacksRegistry.Core.Contracts.IPackSignatureVerifier
|
|
{
|
|
public Task<bool> VerifyAsync(byte[] content, string digest, string? signature, CancellationToken cancellationToken = default)
|
|
=> Task.FromResult(false);
|
|
}
|
|
}
|