Files
git.stella-ops.org/src/Policy/__Tests/StellaOps.Policy.Tests/Replay/VerdictComparerTests.cs
StellaOps Bot 5146204f1b feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
2025-12-22 23:21:21 +02:00

128 lines
4.6 KiB
C#

using FluentAssertions;
using StellaOps.Policy.Replay;
using Xunit;
namespace StellaOps.Policy.Tests.Replay;
public sealed class VerdictComparerTests
{
private readonly VerdictComparer _comparer = new();
[Fact]
public void Compare_IdenticalVerdicts_ReturnsExactMatch()
{
var verdict = CreateVerdict(decision: ReplayDecision.Pass, score: 85.5m);
var result = _comparer.Compare(verdict, verdict, VerdictComparisonOptions.Default);
result.MatchStatus.Should().Be(ReplayMatchStatus.ExactMatch);
result.IsDeterministic.Should().BeTrue();
result.DeterminismConfidence.Should().Be(1.0m);
result.Differences.Should().BeEmpty();
}
[Fact]
public void Compare_DifferentDecisions_ReturnsMismatch()
{
var original = CreateVerdict(decision: ReplayDecision.Pass);
var replayed = CreateVerdict(decision: ReplayDecision.Fail);
var result = _comparer.Compare(replayed, original, VerdictComparisonOptions.Default);
result.MatchStatus.Should().Be(ReplayMatchStatus.Mismatch);
result.IsDeterministic.Should().BeFalse();
result.Differences.Should().Contain(d => d.Field == "Decision");
}
[Fact]
public void Compare_ScoreWithinTolerance_ReturnsMatchWithinTolerance()
{
var original = CreateVerdict(score: 85.5000m);
var replayed = CreateVerdict(score: 85.5005m);
var result = _comparer.Compare(replayed, original,
new VerdictComparisonOptions { ScoreTolerance = 0.001m, TreatMinorAsMatch = true });
result.MatchStatus.Should().Be(ReplayMatchStatus.MatchWithinTolerance);
}
[Fact]
public void Compare_ScoreBeyondTolerance_ReturnsMismatch()
{
var original = CreateVerdict(score: 85.5m);
var replayed = CreateVerdict(score: 86.0m);
var result = _comparer.Compare(replayed, original,
new VerdictComparisonOptions { ScoreTolerance = 0.001m, CriticalScoreTolerance = 0.1m });
result.MatchStatus.Should().Be(ReplayMatchStatus.Mismatch);
result.Differences.Should().Contain(d => d.Field == "Score");
}
[Fact]
public void Compare_DifferentFindings_DetectsAddedAndRemoved()
{
var original = CreateVerdictWithFindings("CVE-2024-001", "CVE-2024-002");
var replayed = CreateVerdictWithFindings("CVE-2024-001", "CVE-2024-003");
var result = _comparer.Compare(replayed, original, VerdictComparisonOptions.Default);
result.MatchStatus.Should().Be(ReplayMatchStatus.Mismatch);
result.Differences.Should().Contain(d => d.Field == "Finding:CVE-2024-002" && d.ReplayedValue == "absent");
result.Differences.Should().Contain(d => d.Field == "Finding:CVE-2024-003" && d.OriginalValue == "absent");
}
[Fact]
public void Compare_SameFindings_DifferentOrder_ReturnsMatch()
{
var original = CreateVerdictWithFindings("CVE-2024-001", "CVE-2024-002", "CVE-2024-003");
var replayed = CreateVerdictWithFindings("CVE-2024-003", "CVE-2024-001", "CVE-2024-002");
var result = _comparer.Compare(replayed, original, VerdictComparisonOptions.Default);
result.MatchStatus.Should().Be(ReplayMatchStatus.ExactMatch);
}
[Fact]
public void Compare_ExtraFindings_DetectsAdditions()
{
var original = CreateVerdictWithFindings("CVE-2024-001");
var replayed = CreateVerdictWithFindings("CVE-2024-001", "CVE-2024-002");
var result = _comparer.Compare(replayed, original, VerdictComparisonOptions.Default);
result.MatchStatus.Should().Be(ReplayMatchStatus.Mismatch);
result.Differences.Should().ContainSingle(d => d.Field == "Finding:CVE-2024-002");
}
[Fact]
public void Compare_CalculatesCorrectConfidence()
{
var original = CreateVerdict(decision: ReplayDecision.Pass, score: 85.0m);
var replayed = CreateVerdict(decision: ReplayDecision.Fail, score: 75.0m);
var result = _comparer.Compare(replayed, original, VerdictComparisonOptions.Default);
result.DeterminismConfidence.Should().BeLessThan(1.0m);
result.DeterminismConfidence.Should().BeGreaterThanOrEqualTo(0m);
}
private static ReplayedVerdict CreateVerdict(
ReplayDecision decision = ReplayDecision.Pass,
decimal score = 85.0m) => new()
{
ArtifactDigest = "sha256:test123",
Decision = decision,
Score = score,
FindingIds = []
};
private static ReplayedVerdict CreateVerdictWithFindings(params string[] findingIds) => new()
{
ArtifactDigest = "sha256:test123",
Decision = ReplayDecision.Pass,
Score = 85.0m,
FindingIds = findingIds.ToList()
};
}