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
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:
132
src/StellaOps.Vexer.Export.Tests/ExportEngineTests.cs
Normal file
132
src/StellaOps.Vexer.Export.Tests/ExportEngineTests.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\StellaOps.Vexer.Export\StellaOps.Vexer.Export.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user