Files
git.stella-ops.org/tests/interop/StellaOps.Interop.Tests/Analysis/FindingsParityAnalyzer.cs

118 lines
4.2 KiB
C#

namespace StellaOps.Interop.Tests.Analysis;
/// <summary>
/// Analyzes and categorizes differences between tool findings.
/// </summary>
public sealed class FindingsParityAnalyzer
{
/// <summary>
/// Categorizes differences between tools.
/// </summary>
public ParityAnalysisReport Analyze(
IReadOnlyList<Finding> stellaFindings,
IReadOnlyList<GrypeFinding> grypeFindings)
{
var differences = new List<FindingDifference>();
// Category 1: Version matching differences
// (e.g., semver vs non-semver interpretation)
var versionDiffs = AnalyzeVersionMatchingDifferences(stellaFindings, grypeFindings);
differences.AddRange(versionDiffs);
// Category 2: Feed coverage differences
// (e.g., Stella has feed X, Grype doesn't)
var feedDiffs = AnalyzeFeedCoverageDifferences(stellaFindings, grypeFindings);
differences.AddRange(feedDiffs);
// Category 3: Package identification differences
// (e.g., different PURL generation)
var purlDiffs = AnalyzePurlDifferences(stellaFindings, grypeFindings);
differences.AddRange(purlDiffs);
// Category 4: VEX application differences
// (e.g., Stella applies VEX, Grype doesn't)
var vexDiffs = AnalyzeVexDifferences(stellaFindings, grypeFindings);
differences.AddRange(vexDiffs);
return new ParityAnalysisReport
{
TotalDifferences = differences.Count,
VersionMatchingDifferences = versionDiffs,
FeedCoverageDifferences = feedDiffs,
PurlDifferences = purlDiffs,
VexDifferences = vexDiffs,
AcceptableDifferences = differences.Count(d => d.IsAcceptable),
RequiresInvestigation = differences.Count(d => !d.IsAcceptable)
};
}
private static List<FindingDifference> AnalyzeVersionMatchingDifferences(
IReadOnlyList<Finding> stellaFindings,
IReadOnlyList<GrypeFinding> grypeFindings)
{
var differences = new List<FindingDifference>();
// TODO: Implement version matching analysis
// Compare how Stella and Grype interpret version ranges
// e.g., >=1.0.0 vs ^1.0.0
return differences;
}
private static List<FindingDifference> AnalyzeFeedCoverageDifferences(
IReadOnlyList<Finding> stellaFindings,
IReadOnlyList<GrypeFinding> grypeFindings)
{
var differences = new List<FindingDifference>();
// TODO: Implement feed coverage analysis
// Identify which vulnerabilities come from feeds only one tool has
// e.g., Stella has GHSA, Grype doesn't, or vice versa
return differences;
}
private static List<FindingDifference> AnalyzePurlDifferences(
IReadOnlyList<Finding> stellaFindings,
IReadOnlyList<GrypeFinding> grypeFindings)
{
var differences = new List<FindingDifference>();
// TODO: Implement PURL difference analysis
// Compare how packages are identified
// e.g., pkg:npm/package vs pkg:npm/package@version
return differences;
}
private static List<FindingDifference> AnalyzeVexDifferences(
IReadOnlyList<Finding> stellaFindings,
IReadOnlyList<GrypeFinding> grypeFindings)
{
var differences = new List<FindingDifference>();
// TODO: Implement VEX application analysis
// Stella applies VEX documents, Grype may not
// This is an acceptable difference
return differences;
}
}
public sealed class ParityAnalysisReport
{
public int TotalDifferences { get; init; }
public IReadOnlyList<FindingDifference> VersionMatchingDifferences { get; init; } = [];
public IReadOnlyList<FindingDifference> FeedCoverageDifferences { get; init; } = [];
public IReadOnlyList<FindingDifference> PurlDifferences { get; init; } = [];
public IReadOnlyList<FindingDifference> VexDifferences { get; init; } = [];
public int AcceptableDifferences { get; init; }
public int RequiresInvestigation { get; init; }
}
public sealed record FindingDifference(
string Category,
string Description,
bool IsAcceptable,
string? Reason = null);