commit and up
Some checks failed
Build Test Deploy / build-test (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
2025-10-07 08:33:54 +03:00
parent bb7eda17a8
commit 304118b665
585 changed files with 3138 additions and 1096 deletions

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Security.Cryptography;
using StellaOps.Feedser.Exporter.TrivyDb;
namespace StellaOps.Feedser.Exporter.TrivyDb.Tests;
public sealed class TrivyDbOciWriterTests : IDisposable
{
private readonly string _root;
public TrivyDbOciWriterTests()
{
_root = Directory.CreateTempSubdirectory("feedser-trivy-oci-tests").FullName;
}
[Fact]
public async Task WritesOciLayoutWithManifestIndex()
{
var metadata = Encoding.UTF8.GetBytes("{\"generatedAt\":\"2024-08-01T00:00:00Z\",\"schema\":1}");
var archive = Enumerable.Range(0, 128).Select(static b => (byte)b).ToArray();
var generatedAt = DateTimeOffset.Parse("2024-08-01T00:00:00Z");
var archivePath = Path.Combine(_root, "db.bin");
File.WriteAllBytes(archivePath, archive);
var archiveDigest = ComputeDigest(archive);
var request = new TrivyDbPackageRequest(metadata, archivePath, archiveDigest, archive.LongLength, generatedAt, "2024.08.01");
var builder = new TrivyDbPackageBuilder();
var package = builder.BuildPackage(request);
var writer = new TrivyDbOciWriter();
var result = await writer.WriteAsync(package, Path.Combine(_root, "oci"), "feedser:v2024.08.01", CancellationToken.None);
Assert.Equal(package.Manifest.Layers[0].Digest, package.Config.DatabaseDigest);
Assert.NotEmpty(result.BlobDigests);
Assert.Contains(result.ManifestDigest, result.BlobDigests);
var layoutPath = Path.Combine(result.RootDirectory, "oci-layout");
Assert.True(File.Exists(layoutPath));
var layoutJson = await File.ReadAllTextAsync(layoutPath, CancellationToken.None);
Assert.Contains("\"imageLayoutVersion\":\"1.0.0\"", layoutJson, StringComparison.Ordinal);
var metadataPath = Path.Combine(result.RootDirectory, "metadata.json");
Assert.True(File.Exists(metadataPath));
var roundTripMetadata = await File.ReadAllBytesAsync(metadataPath, CancellationToken.None);
Assert.Equal(metadata, roundTripMetadata);
var indexPath = Path.Combine(result.RootDirectory, "index.json");
Assert.True(File.Exists(indexPath));
using var indexDocument = JsonDocument.Parse(await File.ReadAllBytesAsync(indexPath, CancellationToken.None));
var manifestElement = indexDocument.RootElement.GetProperty("manifests")[0];
Assert.Equal(result.ManifestDigest, manifestElement.GetProperty("digest").GetString());
Assert.Equal(TrivyDbMediaTypes.OciManifest, manifestElement.GetProperty("mediaType").GetString());
Assert.Equal("feedser:v2024.08.01", manifestElement.GetProperty("annotations").GetProperty("org.opencontainers.image.ref.name").GetString());
var manifestPath = Path.Combine(result.RootDirectory, "blobs", "sha256", result.ManifestDigest.Split(':')[1]);
var manifestBytes = await File.ReadAllBytesAsync(manifestPath, CancellationToken.None);
using var manifestDocument = JsonDocument.Parse(manifestBytes);
var configDescriptor = manifestDocument.RootElement.GetProperty("config");
Assert.Equal(package.Manifest.Config.Digest, configDescriptor.GetProperty("digest").GetString());
Assert.Equal(package.Manifest.Config.MediaType, configDescriptor.GetProperty("mediaType").GetString());
var layer = manifestDocument.RootElement.GetProperty("layers")[0];
Assert.Equal(package.Manifest.Layers[0].Digest, layer.GetProperty("digest").GetString());
Assert.Equal(package.Manifest.Layers[0].MediaType, layer.GetProperty("mediaType").GetString());
foreach (var digest in package.Blobs.Keys)
{
var blobPath = Path.Combine(result.RootDirectory, "blobs", "sha256", digest.Split(':')[1]);
Assert.True(File.Exists(blobPath));
}
}
[Fact]
public async Task ThrowsOnUnsupportedDigest()
{
var package = new TrivyDbPackage(
new OciManifest(2, TrivyDbMediaTypes.OciManifest, new OciDescriptor(TrivyDbMediaTypes.TrivyConfig, "sha256:abcd", 4), Array.Empty<OciDescriptor>()),
new TrivyConfigDocument(TrivyDbMediaTypes.TrivyConfig, DateTimeOffset.UtcNow, "1", "sha256:abcd", 4),
new Dictionary<string, TrivyDbBlob>
{
["md5:deadbeef"] = TrivyDbBlob.FromBytes(new byte[] { 1, 2, 3, 4 }),
},
new byte[] { 123 });
var writer = new TrivyDbOciWriter();
await Assert.ThrowsAsync<InvalidOperationException>(() => writer.WriteAsync(package, Path.Combine(_root, "invalid"), "feedser:bad", CancellationToken.None));
}
public void Dispose()
{
try
{
if (Directory.Exists(_root))
{
Directory.Delete(_root, recursive: true);
}
}
catch
{
// ignore cleanup issues
}
}
private static string ComputeDigest(byte[] payload)
{
var hash = SHA256.HashData(payload);
return "sha256:" + Convert.ToHexString(hash).ToLowerInvariant();
}
}