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.
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
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()
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user