Files
git.stella-ops.org/src/Policy/__Tests/StellaOps.Policy.Tests/Deltas/DeltaVerdictTests.cs
StellaOps Bot b9f71fc7e9 sprints work
2025-12-24 21:46:08 +02:00

246 lines
7.5 KiB
C#

using FluentAssertions;
using StellaOps.Policy.Deltas;
using Xunit;
namespace StellaOps.Policy.Tests.Deltas;
public sealed class DeltaVerdictTests
{
[Fact]
public void Build_WithNoDrivers_ReturnsPass()
{
var verdict = new DeltaVerdictBuilder()
.Build("delta:sha256:test");
verdict.Status.Should().Be(DeltaVerdictStatus.Pass);
verdict.Explanation.Should().Contain("No blocking");
}
[Fact]
public void Build_WithWarningDriver_ReturnsWarn()
{
var driver = new DeltaDriver
{
Type = "new-package",
Severity = DeltaDriverSeverity.Low,
Description = "New package added"
};
var verdict = new DeltaVerdictBuilder()
.AddWarningDriver(driver)
.Build("delta:sha256:test");
verdict.Status.Should().Be(DeltaVerdictStatus.Warn);
verdict.WarningDrivers.Should().HaveCount(1);
}
[Fact]
public void Build_WithBlockingDriver_ReturnsFail()
{
var driver = new DeltaDriver
{
Type = "new-reachable-cve",
Severity = DeltaDriverSeverity.Critical,
Description = "Critical CVE is now reachable",
CveId = "CVE-2024-001"
};
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.Build("delta:sha256:test");
verdict.Status.Should().Be(DeltaVerdictStatus.Fail);
verdict.BlockingDrivers.Should().HaveCount(1);
verdict.RecommendedGate.Should().Be(DeltaGateLevel.G4);
}
[Fact]
public void Build_WithBlockingDriverAndException_ReturnsPassWithExceptions()
{
var driver = new DeltaDriver
{
Type = "new-reachable-cve",
Severity = DeltaDriverSeverity.Critical,
Description = "Critical CVE is now reachable",
CveId = "CVE-2024-001"
};
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.AddException("exception-123")
.Build("delta:sha256:test");
verdict.Status.Should().Be(DeltaVerdictStatus.PassWithExceptions);
verdict.AppliedExceptions.Should().Contain("exception-123");
}
[Fact]
public void Build_CriticalDriver_EscalatesToG4()
{
var driver = new DeltaDriver
{
Type = "critical-issue",
Severity = DeltaDriverSeverity.Critical,
Description = "Critical issue"
};
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.Build("delta:sha256:test");
verdict.RecommendedGate.Should().Be(DeltaGateLevel.G4);
}
[Fact]
public void Build_HighDriver_EscalatesToG3()
{
var driver = new DeltaDriver
{
Type = "high-issue",
Severity = DeltaDriverSeverity.High,
Description = "High severity issue"
};
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.Build("delta:sha256:test");
verdict.RecommendedGate.Should().Be(DeltaGateLevel.G3);
}
[Fact]
public void Build_WithRiskPoints_SetsCorrectValue()
{
var verdict = new DeltaVerdictBuilder()
.WithRiskPoints(25)
.Build("delta:sha256:test");
verdict.RiskPoints.Should().Be(25);
}
[Fact]
public void Build_WithRecommendations_IncludesAll()
{
var verdict = new DeltaVerdictBuilder()
.AddRecommendation("Review CVE-2024-001")
.AddRecommendation("Update dependency")
.Build("delta:sha256:test");
verdict.Recommendations.Should().HaveCount(2);
verdict.Recommendations.Should().Contain("Review CVE-2024-001");
}
[Fact]
public void Build_WithCustomExplanation_UsesProvided()
{
var verdict = new DeltaVerdictBuilder()
.WithExplanation("Custom explanation")
.Build("delta:sha256:test");
verdict.Explanation.Should().Be("Custom explanation");
}
[Fact]
public void Build_GeneratesDeterministicVerdictId_ForIdenticalInputs()
{
var verdict1 = new DeltaVerdictBuilder().Build("delta:sha256:test");
var verdict2 = new DeltaVerdictBuilder().Build("delta:sha256:test");
// Content-addressed IDs are deterministic
verdict1.VerdictId.Should().StartWith("verdict:sha256:");
verdict1.VerdictId.Should().Be(verdict2.VerdictId, "identical inputs must produce identical VerdictId");
}
[Fact]
public void Build_GeneratesDifferentVerdictId_ForDifferentInputs()
{
var verdict1 = new DeltaVerdictBuilder().Build("delta:sha256:test1");
var verdict2 = new DeltaVerdictBuilder().Build("delta:sha256:test2");
verdict1.VerdictId.Should().StartWith("verdict:sha256:");
verdict2.VerdictId.Should().StartWith("verdict:sha256:");
verdict1.VerdictId.Should().NotBe(verdict2.VerdictId, "different inputs must produce different VerdictId");
}
[Theory]
[InlineData(10)]
public void Build_IsIdempotent_AcrossMultipleIterations(int iterations)
{
var driver = new DeltaDriver
{
Type = "new-reachable-cve",
Severity = DeltaDriverSeverity.High,
Description = "High severity CVE",
CveId = "CVE-2024-999"
};
var expected = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.Build("delta:sha256:determinism-test")
.VerdictId;
for (int i = 0; i < iterations; i++)
{
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.Build("delta:sha256:determinism-test");
verdict.VerdictId.Should().Be(expected, $"iteration {i}: VerdictId must be stable");
}
}
[Fact]
public void Build_VerdictIdIsDeterministic_RegardlessOfDriverAddOrder()
{
var driver1 = new DeltaDriver
{
Type = "aaa-first",
Severity = DeltaDriverSeverity.Medium,
Description = "First driver"
};
var driver2 = new DeltaDriver
{
Type = "zzz-last",
Severity = DeltaDriverSeverity.Low,
Description = "Second driver"
};
// Add in one order
var verdict1 = new DeltaVerdictBuilder()
.AddWarningDriver(driver1)
.AddWarningDriver(driver2)
.Build("delta:sha256:order-test");
// Add in reverse order
var verdict2 = new DeltaVerdictBuilder()
.AddWarningDriver(driver2)
.AddWarningDriver(driver1)
.Build("delta:sha256:order-test");
// Content-addressed IDs should be same because drivers are sorted by Type
verdict1.VerdictId.Should().Be(verdict2.VerdictId, "drivers are sorted by Type before hashing");
}
[Fact]
public void VerdictIdGenerator_ComputeFromVerdict_MatchesOriginal()
{
var driver = new DeltaDriver
{
Type = "recompute-test",
Severity = DeltaDriverSeverity.Critical,
Description = "Test driver"
};
var verdict = new DeltaVerdictBuilder()
.AddBlockingDriver(driver)
.AddException("EXCEPTION-001")
.Build("delta:sha256:recompute-test");
var generator = new VerdictIdGenerator();
var recomputed = generator.ComputeVerdictId(verdict);
recomputed.Should().Be(verdict.VerdictId, "recomputed VerdictId must match original");
}
}