- 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.
153 lines
4.2 KiB
C#
153 lines
4.2 KiB
C#
namespace StellaOps.Scanner.Benchmark.Metrics;
|
|
|
|
/// <summary>
|
|
/// Benchmark metrics for comparing scanner accuracy.
|
|
/// </summary>
|
|
public sealed record BenchmarkMetrics
|
|
{
|
|
/// <summary>
|
|
/// Number of true positive findings.
|
|
/// </summary>
|
|
public required int TruePositives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Number of false positive findings.
|
|
/// </summary>
|
|
public required int FalsePositives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Number of true negative findings.
|
|
/// </summary>
|
|
public required int TrueNegatives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Number of false negative findings (missed vulnerabilities).
|
|
/// </summary>
|
|
public required int FalseNegatives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Precision = TP / (TP + FP).
|
|
/// </summary>
|
|
public double Precision => TruePositives + FalsePositives > 0
|
|
? (double)TruePositives / (TruePositives + FalsePositives)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// Recall = TP / (TP + FN).
|
|
/// </summary>
|
|
public double Recall => TruePositives + FalseNegatives > 0
|
|
? (double)TruePositives / (TruePositives + FalseNegatives)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// F1 Score = 2 * (Precision * Recall) / (Precision + Recall).
|
|
/// </summary>
|
|
public double F1Score => Precision + Recall > 0
|
|
? 2 * (Precision * Recall) / (Precision + Recall)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// Accuracy = (TP + TN) / (TP + TN + FP + FN).
|
|
/// </summary>
|
|
public double Accuracy
|
|
{
|
|
get
|
|
{
|
|
var total = TruePositives + TrueNegatives + FalsePositives + FalseNegatives;
|
|
return total > 0 ? (double)(TruePositives + TrueNegatives) / total : 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The scanner tool name.
|
|
/// </summary>
|
|
public required string ToolName { get; init; }
|
|
|
|
/// <summary>
|
|
/// The image reference that was scanned.
|
|
/// </summary>
|
|
public string? ImageRef { get; init; }
|
|
|
|
/// <summary>
|
|
/// Timestamp when the benchmark was run.
|
|
/// </summary>
|
|
public required DateTimeOffset Timestamp { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aggregated metrics across multiple images.
|
|
/// </summary>
|
|
public sealed record AggregatedMetrics
|
|
{
|
|
/// <summary>
|
|
/// The scanner tool name.
|
|
/// </summary>
|
|
public required string ToolName { get; init; }
|
|
|
|
/// <summary>
|
|
/// Total images scanned.
|
|
/// </summary>
|
|
public required int TotalImages { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sum of true positives across all images.
|
|
/// </summary>
|
|
public required int TotalTruePositives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sum of false positives across all images.
|
|
/// </summary>
|
|
public required int TotalFalsePositives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sum of true negatives across all images.
|
|
/// </summary>
|
|
public required int TotalTrueNegatives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sum of false negatives across all images.
|
|
/// </summary>
|
|
public required int TotalFalseNegatives { get; init; }
|
|
|
|
/// <summary>
|
|
/// Aggregate precision.
|
|
/// </summary>
|
|
public double Precision => TotalTruePositives + TotalFalsePositives > 0
|
|
? (double)TotalTruePositives / (TotalTruePositives + TotalFalsePositives)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// Aggregate recall.
|
|
/// </summary>
|
|
public double Recall => TotalTruePositives + TotalFalseNegatives > 0
|
|
? (double)TotalTruePositives / (TotalTruePositives + TotalFalseNegatives)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// Aggregate F1 score.
|
|
/// </summary>
|
|
public double F1Score => Precision + Recall > 0
|
|
? 2 * (Precision * Recall) / (Precision + Recall)
|
|
: 0;
|
|
|
|
/// <summary>
|
|
/// Breakdown by severity.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<string, BenchmarkMetrics>? BySeverity { get; init; }
|
|
|
|
/// <summary>
|
|
/// Breakdown by ecosystem.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<string, BenchmarkMetrics>? ByEcosystem { get; init; }
|
|
|
|
/// <summary>
|
|
/// Individual image metrics.
|
|
/// </summary>
|
|
public IReadOnlyList<BenchmarkMetrics>? PerImageMetrics { get; init; }
|
|
|
|
/// <summary>
|
|
/// Timestamp when the aggregation was computed.
|
|
/// </summary>
|
|
public required DateTimeOffset Timestamp { get; init; }
|
|
}
|