audit work, fixed StellaOps.sln warnings/errors, fixed tests, sprints work, new advisories

This commit is contained in:
master
2026-01-07 18:49:59 +02:00
parent 04ec098046
commit 608a7f85c0
866 changed files with 56323 additions and 6231 deletions

View File

@@ -0,0 +1,257 @@
// -----------------------------------------------------------------------------
// SignalSnapshotBuilderTests.cs
// Sprint: SPRINT_20260106_001_004_BE_determinization_integration
// Task: DBI-019 - Write unit tests for SignalSnapshotBuilder
// Description: Unit tests for parallel signal snapshot building
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Time.Testing;
using Moq;
using StellaOps.Findings.Ledger.Observations;
using Xunit;
namespace StellaOps.Findings.Ledger.Tests.Observations;
[Trait("Category", "Unit")]
public sealed class SignalSnapshotBuilderTests
{
private readonly FakeTimeProvider _timeProvider = new();
private readonly Mock<ISignalProvider> _epssMock = new();
private readonly Mock<ISignalProvider> _kevMock = new();
private readonly Mock<ISignalProvider> _vexMock = new();
private readonly Mock<ISignalProvider> _reachabilityMock = new();
public SignalSnapshotBuilderTests()
{
_timeProvider.SetUtcNow(new DateTimeOffset(2026, 1, 7, 12, 0, 0, TimeSpan.Zero));
_epssMock.Setup(x => x.SignalType).Returns("epss");
_kevMock.Setup(x => x.SignalType).Returns("kev");
_vexMock.Setup(x => x.SignalType).Returns("vex");
_reachabilityMock.Setup(x => x.SignalType).Returns("reachability");
}
private SignalSnapshotBuilder CreateBuilder(params ISignalProvider[] providers)
{
return new SignalSnapshotBuilder(
providers,
_timeProvider,
NullLogger<SignalSnapshotBuilder>.Instance);
}
[Fact]
public async Task BuildAsync_FetchesAllSignalsInParallel()
{
// Arrange
var cveId = "CVE-2024-1234";
var product = "pkg:npm/lodash@4.17.0";
_epssMock
.Setup(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Score: 0.85", new { Score = 0.85 }));
_kevMock
.Setup(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("IN KEV", new { IsInKev = true }));
_vexMock
.Setup(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("not_affected"));
_reachabilityMock
.Setup(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Reachable"));
var builder = CreateBuilder(_epssMock.Object, _kevMock.Object, _vexMock.Object, _reachabilityMock.Object);
// Act
var snapshot = await builder.BuildAsync(cveId, product);
// Assert
Assert.Equal(cveId, snapshot.CveId);
Assert.Equal(product, snapshot.Product);
Assert.Equal(SignalResultStatus.Available, snapshot.Epss.Status);
Assert.Equal(SignalResultStatus.Available, snapshot.Kev.Status);
Assert.Equal(SignalResultStatus.Available, snapshot.Vex.Status);
Assert.Equal(SignalResultStatus.Available, snapshot.Reachability.Status);
Assert.Empty(snapshot.FailedSignals);
_epssMock.Verify(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()), Times.Once);
_kevMock.Verify(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()), Times.Once);
_vexMock.Verify(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()), Times.Once);
_reachabilityMock.Verify(x => x.FetchAsync(cveId, product, It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task BuildAsync_MissingProvider_ReturnsNotConfigured()
{
// Arrange - only EPSS provider available
_epssMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Score: 0.5"));
var builder = CreateBuilder(_epssMock.Object);
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert
Assert.Equal(SignalResultStatus.Available, snapshot.Epss.Status);
Assert.Equal(SignalResultStatus.NotConfigured, snapshot.Kev.Status);
Assert.Equal(SignalResultStatus.NotConfigured, snapshot.Vex.Status);
Assert.Equal(SignalResultStatus.NotConfigured, snapshot.Reachability.Status);
}
[Fact]
public async Task BuildAsync_ProviderThrows_ReturnsFailed()
{
// Arrange
_epssMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new InvalidOperationException("Connection refused"));
var builder = CreateBuilder(_epssMock.Object);
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert
Assert.Equal(SignalResultStatus.Failed, snapshot.Epss.Status);
Assert.Equal("Connection refused", snapshot.Epss.Error);
Assert.Contains("epss", snapshot.FailedSignals);
}
[Fact]
public async Task BuildAsync_ProviderNotFound_ReturnsNotFound()
{
// Arrange
_epssMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.NotFound("epss-feed"));
var builder = CreateBuilder(_epssMock.Object);
// Act
var snapshot = await builder.BuildAsync("CVE-2099-9999", "pkg:npm/test@1.0.0");
// Assert
Assert.Equal(SignalResultStatus.NotFound, snapshot.Epss.Status);
Assert.DoesNotContain("epss", snapshot.FailedSignals); // NotFound is not a failure
}
[Fact]
public async Task BuildAsync_ComputesUncertaintyScore()
{
// Arrange - all signals available = low uncertainty
SetupAllSignalsAvailable();
var builder = CreateBuilder(_epssMock.Object, _kevMock.Object, _vexMock.Object, _reachabilityMock.Object);
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert - with all signals, uncertainty should be low
Assert.True(snapshot.UncertaintyScore < 0.2);
}
[Fact]
public async Task BuildAsync_NoSignals_HighUncertainty()
{
// Arrange - no providers configured
var builder = CreateBuilder();
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert - with no signals, uncertainty should be high
Assert.Equal(1.0, snapshot.UncertaintyScore);
}
[Fact]
public async Task BuildAsync_SnapshotAtUsesTimeProvider()
{
// Arrange
var expectedTime = new DateTimeOffset(2026, 1, 7, 12, 0, 0, TimeSpan.Zero);
var builder = CreateBuilder();
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert
Assert.Equal(expectedTime, snapshot.SnapshotAt);
}
[Fact]
public async Task BuildBatchAsync_ProcessesMultiplePairs()
{
// Arrange
SetupAllSignalsAvailable();
var builder = CreateBuilder(_epssMock.Object, _kevMock.Object, _vexMock.Object, _reachabilityMock.Object);
var pairs = new List<(string CveId, string Product)>
{
("CVE-2024-0001", "pkg:npm/foo@1.0.0"),
("CVE-2024-0002", "pkg:npm/bar@2.0.0"),
("CVE-2024-0003", "pkg:npm/baz@3.0.0")
};
// Act
var results = await builder.BuildBatchAsync(pairs);
// Assert
Assert.Equal(3, results.Count);
Assert.All(pairs, pair => Assert.True(results.ContainsKey(pair)));
}
[Fact]
public async Task BuildAsync_TracksFailedSignals()
{
// Arrange
_epssMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("EPSS error"));
_kevMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Not in KEV"));
_vexMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception("VEX error"));
_reachabilityMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Reachable"));
var builder = CreateBuilder(_epssMock.Object, _kevMock.Object, _vexMock.Object, _reachabilityMock.Object);
// Act
var snapshot = await builder.BuildAsync("CVE-2024-1234", "pkg:npm/test@1.0.0");
// Assert
Assert.Equal(2, snapshot.FailedSignals.Count);
Assert.Contains("epss", snapshot.FailedSignals);
Assert.Contains("vex", snapshot.FailedSignals);
}
private void SetupAllSignalsAvailable()
{
_epssMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Score: 0.5"));
_kevMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Not in KEV"));
_vexMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("not_affected"));
_reachabilityMock
.Setup(x => x.FetchAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(SignalResult.Available("Reachable"));
}
}