using System; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.Json; using StellaOps.Concelier.Exporter.TrivyDb; namespace StellaOps.Concelier.Exporter.TrivyDb.Tests; public sealed class TrivyDbPackageBuilderTests { [Fact] public void BuildsOciManifestWithExpectedMediaTypes() { var metadata = Encoding.UTF8.GetBytes("{\"generatedAt\":\"2024-07-15T12:00:00Z\"}"); var archive = Enumerable.Range(0, 256).Select(static b => (byte)b).ToArray(); var archivePath = Path.GetTempFileName(); File.WriteAllBytes(archivePath, archive); var archiveDigest = ComputeDigest(archive); try { var request = new TrivyDbPackageRequest( metadata, archivePath, archiveDigest, archive.LongLength, DateTimeOffset.Parse("2024-07-15T12:00:00Z"), "2024.07.15"); var builder = new TrivyDbPackageBuilder(); var package = builder.BuildPackage(request); Assert.Equal(TrivyDbMediaTypes.OciManifest, package.Manifest.MediaType); Assert.Equal(TrivyDbMediaTypes.TrivyConfig, package.Manifest.Config.MediaType); var layer = Assert.Single(package.Manifest.Layers); Assert.Equal(TrivyDbMediaTypes.TrivyLayer, layer.MediaType); var configBytes = JsonSerializer.SerializeToUtf8Bytes(package.Config, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); var expectedConfigDigest = ComputeDigest(configBytes); Assert.Equal(expectedConfigDigest, package.Manifest.Config.Digest); Assert.Equal(archiveDigest, layer.Digest); Assert.True(package.Blobs.ContainsKey(archiveDigest)); Assert.Equal(archive.LongLength, package.Blobs[archiveDigest].Length); Assert.True(package.Blobs.ContainsKey(expectedConfigDigest)); Assert.Equal(metadata, package.MetadataJson.ToArray()); } finally { if (File.Exists(archivePath)) { File.Delete(archivePath); } } } [Fact] public void ThrowsWhenMetadataMissing() { var builder = new TrivyDbPackageBuilder(); var archivePath = Path.GetTempFileName(); var archiveBytes = new byte[] { 1, 2, 3 }; File.WriteAllBytes(archivePath, archiveBytes); var digest = ComputeDigest(archiveBytes); try { Assert.Throws(() => builder.BuildPackage(new TrivyDbPackageRequest( ReadOnlyMemory.Empty, archivePath, digest, archiveBytes.LongLength, DateTimeOffset.UtcNow, "1"))); } finally { if (File.Exists(archivePath)) { File.Delete(archivePath); } } } private static string ComputeDigest(ReadOnlySpan payload) { var hash = SHA256.HashData(payload); var hex = Convert.ToHexString(hash); return "sha256:" + hex.ToLowerInvariant(); } }