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 { ["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(() => 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 VerifyAsync(byte[] content, string digest, string? signature, CancellationToken cancellationToken = default) => Task.FromResult(false); } }