107 lines
2.9 KiB
C#
107 lines
2.9 KiB
C#
using System.Text;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using StellaOps.Concelier.SbomIntegration.Models;
|
|
using StellaOps.Concelier.SbomIntegration.Parsing;
|
|
using StellaOps.Concelier.SbomIntegration.Vex;
|
|
using StellaOps.TestKit;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.Concelier.SbomIntegration.Tests;
|
|
|
|
public sealed class VexIntegrationTests
|
|
{
|
|
[Trait("Category", TestCategories.Integration)]
|
|
[Fact]
|
|
public async Task ConsumeFromSbomAsync_ParsesEmbeddedCycloneDxVex()
|
|
{
|
|
var json = """
|
|
{
|
|
"bomFormat": "CycloneDX",
|
|
"specVersion": "1.7",
|
|
"serialNumber": "urn:uuid:00000000-0000-0000-0000-000000000001",
|
|
"version": 1,
|
|
"metadata": {
|
|
"timestamp": "2026-01-20T00:00:00Z",
|
|
"component": {
|
|
"bom-ref": "comp-1",
|
|
"type": "library",
|
|
"name": "example",
|
|
"version": "1.0.0",
|
|
"purl": "pkg:npm/example@1.0.0"
|
|
},
|
|
"tools": [
|
|
{
|
|
"vendor": "test",
|
|
"name": "test",
|
|
"version": "1.0"
|
|
}
|
|
]
|
|
},
|
|
"components": [
|
|
{
|
|
"bom-ref": "comp-1",
|
|
"type": "library",
|
|
"name": "example",
|
|
"version": "1.0.0",
|
|
"purl": "pkg:npm/example@1.0.0"
|
|
}
|
|
],
|
|
"vulnerabilities": [
|
|
{
|
|
"id": "CVE-2026-9999",
|
|
"analysis": {
|
|
"state": "not_affected",
|
|
"justification": "component_not_present",
|
|
"response": ["will_not_fix"],
|
|
"detail": "component absent",
|
|
"lastUpdated": "2026-01-20T00:00:00Z"
|
|
},
|
|
"affects": [
|
|
{ "ref": "comp-1" }
|
|
],
|
|
"ratings": [
|
|
{
|
|
"method": "CVSSv3",
|
|
"score": 7.5,
|
|
"severity": "high"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
""";
|
|
|
|
await using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
|
|
var parser = new ParsedSbomParser(NullLogger<ParsedSbomParser>.Instance);
|
|
var sbom = await parser.ParseAsync(stream, SbomFormat.CycloneDX, CancellationToken.None);
|
|
|
|
var consumer = CreateConsumer();
|
|
var result = await consumer.ConsumeFromSbomAsync(sbom, VexConsumptionPolicyDefaults.Default, CancellationToken.None);
|
|
|
|
Assert.Single(result.Statements);
|
|
Assert.Equal("CVE-2026-9999", result.Statements[0].VulnerabilityId);
|
|
Assert.Equal(VexStatus.NotAffected, result.Statements[0].Status);
|
|
Assert.Contains("pkg:npm/example@1.0.0", result.Statements[0].AffectedComponents);
|
|
}
|
|
|
|
private static VexConsumer CreateConsumer()
|
|
{
|
|
var evaluator = new VexTrustEvaluator(new StubTimeProvider());
|
|
var resolver = new VexConflictResolver();
|
|
var merger = new VexMerger(resolver);
|
|
var extractors = new IVexStatementExtractor[]
|
|
{
|
|
new CycloneDxVexExtractor(),
|
|
new SpdxVexExtractor()
|
|
};
|
|
|
|
return new VexConsumer(evaluator, merger, extractors);
|
|
}
|
|
|
|
private sealed class StubTimeProvider : TimeProvider
|
|
{
|
|
public override DateTimeOffset GetUtcNow()
|
|
=> DateTimeOffset.Parse("2026-01-20T01:00:00Z");
|
|
}
|
|
}
|