- 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.
128 lines
4.6 KiB
C#
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()
|
|
};
|
|
}
|