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

This commit is contained in:
root
2025-10-15 19:20:13 +03:00
parent 8d153522b0
commit 0d8233dfb4
125 changed files with 9383 additions and 3306 deletions

View File

@@ -0,0 +1,132 @@
using System;
using System.Collections.Immutable;
using System.IO;
using System.Text;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Vexer.Core;
using StellaOps.Vexer.Export;
using StellaOps.Vexer.Policy;
using StellaOps.Vexer.Storage.Mongo;
using Xunit;
namespace StellaOps.Vexer.Export.Tests;
public sealed class ExportEngineTests
{
[Fact]
public async Task ExportAsync_GeneratesAndCachesManifest()
{
var store = new InMemoryExportStore();
var evaluator = new StaticPolicyEvaluator("baseline/v1");
var dataSource = new InMemoryExportDataSource();
var exporter = new DummyExporter(VexExportFormat.Json);
var engine = new VexExportEngine(store, evaluator, dataSource, new[] { exporter }, NullLogger<VexExportEngine>.Instance);
var query = VexQuery.Create(new[] { new VexQueryFilter("vulnId", "CVE-2025-0001") });
var context = new VexExportRequestContext(query, VexExportFormat.Json, DateTimeOffset.UtcNow, ForceRefresh: false);
var manifest = await engine.ExportAsync(context, CancellationToken.None);
Assert.False(manifest.FromCache);
Assert.Equal(VexExportFormat.Json, manifest.Format);
Assert.Equal("baseline/v1", manifest.ConsensusRevision);
Assert.Equal(1, manifest.ClaimCount);
// second call hits cache
var cached = await engine.ExportAsync(context, CancellationToken.None);
Assert.True(cached.FromCache);
Assert.Equal(manifest.ExportId, cached.ExportId);
}
private sealed class InMemoryExportStore : IVexExportStore
{
private readonly Dictionary<string, VexExportManifest> _store = new(StringComparer.Ordinal);
public ValueTask<VexExportManifest?> FindAsync(VexQuerySignature signature, VexExportFormat format, CancellationToken cancellationToken)
{
var key = CreateKey(signature.Value, format);
_store.TryGetValue(key, out var manifest);
return ValueTask.FromResult<VexExportManifest?>(manifest);
}
public ValueTask SaveAsync(VexExportManifest manifest, CancellationToken cancellationToken)
{
var key = CreateKey(manifest.QuerySignature.Value, manifest.Format);
_store[key] = manifest;
return ValueTask.CompletedTask;
}
private static string CreateKey(string signature, VexExportFormat format)
=> FormattableString.Invariant($"{signature}|{format}");
}
private sealed class StaticPolicyEvaluator : IVexPolicyEvaluator
{
public StaticPolicyEvaluator(string version)
{
Version = version;
}
public string Version { get; }
public VexPolicySnapshot Snapshot => VexPolicySnapshot.Default;
public double GetProviderWeight(VexProvider provider) => 1.0;
public bool IsClaimEligible(VexClaim claim, VexProvider provider, out string? rejectionReason)
{
rejectionReason = null;
return true;
}
}
private sealed class InMemoryExportDataSource : IVexExportDataSource
{
public ValueTask<VexExportDataSet> FetchAsync(VexQuery query, CancellationToken cancellationToken)
{
var claim = new VexClaim(
"CVE-2025-0001",
"vendor",
new VexProduct("pkg:demo/app", "Demo"),
VexClaimStatus.Affected,
new VexClaimDocument(VexDocumentFormat.Csaf, "sha256:demo", new Uri("https://example.org/demo")),
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow);
var consensus = new VexConsensus(
"CVE-2025-0001",
claim.Product,
VexConsensusStatus.Affected,
DateTimeOffset.UtcNow,
new[] { new VexConsensusSource("vendor", VexClaimStatus.Affected, "sha256:demo", 1.0) },
conflicts: null,
policyVersion: "baseline/v1",
summary: "affected");
return ValueTask.FromResult(new VexExportDataSet(
ImmutableArray.Create(consensus),
ImmutableArray.Create(claim),
ImmutableArray.Create("vendor")));
}
}
private sealed class DummyExporter : IVexExporter
{
public DummyExporter(VexExportFormat format)
{
Format = format;
}
public VexExportFormat Format { get; }
public VexContentAddress Digest(VexExportRequest request)
=> new("sha256", "deadbeef");
public ValueTask<VexExportResult> SerializeAsync(VexExportRequest request, Stream output, CancellationToken cancellationToken)
{
var bytes = System.Text.Encoding.UTF8.GetBytes("{}");
output.Write(bytes);
return ValueTask.FromResult(new VexExportResult(new VexContentAddress("sha256", "deadbeef"), bytes.Length, ImmutableDictionary<string, string>.Empty));
}
}
}