Refactor code structure for improved readability and maintainability; optimize performance in key functions.

This commit is contained in:
master
2025-12-22 19:06:31 +02:00
parent dfaa2079aa
commit 4602ccc3a3
1444 changed files with 109919 additions and 8058 deletions

View File

@@ -0,0 +1,395 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using StellaOps.Scanner.Reachability.MiniMap;
using Xunit;
namespace StellaOps.Scanner.Reachability.Tests.MiniMap;
public class MiniMapExtractorTests
{
private readonly MiniMapExtractor _extractor = new();
[Fact]
public void Extract_ReachableComponent_ReturnsPaths()
{
var graph = CreateGraphWithPaths();
var result = _extractor.Extract(graph, "pkg:npm/vulnerable@1.0.0");
result.State.Should().Be(ReachabilityState.StaticReachable);
result.Paths.Should().NotBeEmpty();
result.Entrypoints.Should().NotBeEmpty();
result.Confidence.Should().BeGreaterThan(0.5m);
}
[Fact]
public void Extract_UnreachableComponent_ReturnsEmptyPaths()
{
var graph = CreateGraphWithoutPaths();
var result = _extractor.Extract(graph, "pkg:npm/isolated@1.0.0");
result.State.Should().Be(ReachabilityState.StaticUnreachable);
result.Paths.Should().BeEmpty();
result.Confidence.Should().Be(0.9m); // High confidence in unreachability
}
[Fact]
public void Extract_WithRuntimeEvidence_ReturnsConfirmedReachable()
{
var graph = CreateGraphWithRuntimeEvidence();
var result = _extractor.Extract(graph, "pkg:npm/vulnerable@1.0.0");
result.State.Should().Be(ReachabilityState.ConfirmedReachable);
result.Paths.Should().Contain(p => p.HasRuntimeEvidence);
result.Confidence.Should().BeGreaterThan(0.8m);
}
[Fact]
public void Extract_NonExistentComponent_ReturnsNotFoundMap()
{
var graph = CreateGraphWithPaths();
var result = _extractor.Extract(graph, "pkg:npm/nonexistent@1.0.0");
result.State.Should().Be(ReachabilityState.Unknown);
result.Confidence.Should().Be(0m);
result.VulnerableComponent.Id.Should().Be("pkg:npm/nonexistent@1.0.0");
}
[Fact]
public void Extract_RespectMaxPaths_LimitsResults()
{
var graph = CreateGraphWithManyPaths();
var result = _extractor.Extract(graph, "pkg:npm/vulnerable@1.0.0", maxPaths: 5);
result.Paths.Count.Should().BeLessOrEqualTo(5);
}
[Fact]
public void Extract_ClassifiesEntrypointKinds_Correctly()
{
var graph = CreateGraphWithDifferentEntrypoints();
var result = _extractor.Extract(graph, "pkg:npm/vulnerable@1.0.0");
result.Entrypoints.Should().Contain(e => e.Kind == EntrypointKind.HttpEndpoint);
result.Entrypoints.Should().Contain(e => e.Kind == EntrypointKind.MainFunction);
}
private static RichGraph CreateGraphWithPaths()
{
var nodes = new List<RichGraphNode>
{
new(
Id: "entrypoint:main",
SymbolId: "main",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "main",
Display: "main()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "function:process",
SymbolId: "process",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "function",
Display: "process()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "vuln:component",
SymbolId: "vulnerable",
CodeId: null,
Purl: "pkg:npm/vulnerable@1.0.0",
Lang: "javascript",
Kind: "function",
Display: "vulnerable()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null)
};
var edges = new List<RichGraphEdge>
{
new(
From: "entrypoint:main",
To: "function:process",
Kind: "call",
Purl: null,
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null),
new(
From: "function:process",
To: "vuln:component",
Kind: "call",
Purl: "pkg:npm/vulnerable@1.0.0",
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null)
};
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: Array.Empty<RichGraphRoot>(),
Analyzer: new RichGraphAnalyzer("test", "1.0", null));
}
private static RichGraph CreateGraphWithoutPaths()
{
var nodes = new List<RichGraphNode>
{
new(
Id: "entrypoint:main",
SymbolId: "main",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "main",
Display: "main()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "isolated:component",
SymbolId: "isolated",
CodeId: null,
Purl: "pkg:npm/isolated@1.0.0",
Lang: "javascript",
Kind: "function",
Display: "isolated()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null)
};
// No edges - isolated component
var edges = new List<RichGraphEdge>();
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: Array.Empty<RichGraphRoot>(),
Analyzer: new RichGraphAnalyzer("test", "1.0", null));
}
private static RichGraph CreateGraphWithRuntimeEvidence()
{
var nodes = new List<RichGraphNode>
{
new(
Id: "entrypoint:main",
SymbolId: "main",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "main",
Display: "main()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "vuln:component",
SymbolId: "vulnerable",
CodeId: null,
Purl: "pkg:npm/vulnerable@1.0.0",
Lang: "javascript",
Kind: "function",
Display: "vulnerable()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null)
};
var edges = new List<RichGraphEdge>
{
new(
From: "entrypoint:main",
To: "vuln:component",
Kind: "call",
Purl: "pkg:npm/vulnerable@1.0.0",
SymbolDigest: null,
Evidence: new[] { "runtime", "static" },
Confidence: 0.95,
Candidates: null)
};
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: Array.Empty<RichGraphRoot>(),
Analyzer: new RichGraphAnalyzer("test", "1.0", null));
}
private static RichGraph CreateGraphWithManyPaths()
{
var nodes = new List<RichGraphNode>
{
new(
Id: "entrypoint:main",
SymbolId: "main",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "main",
Display: "main()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "vuln:component",
SymbolId: "vulnerable",
CodeId: null,
Purl: "pkg:npm/vulnerable@1.0.0",
Lang: "javascript",
Kind: "function",
Display: "vulnerable()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null)
};
// Add intermediate nodes to create multiple paths
for (int i = 1; i <= 10; i++)
{
nodes.Add(new RichGraphNode(
Id: $"function:intermediate{i}",
SymbolId: $"intermediate{i}",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "function",
Display: $"intermediate{i}()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null));
}
var edges = new List<RichGraphEdge>();
// Create multiple paths from main to vuln through different intermediates
for (int i = 1; i <= 10; i++)
{
edges.Add(new RichGraphEdge(
From: "entrypoint:main",
To: $"function:intermediate{i}",
Kind: "call",
Purl: null,
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null));
edges.Add(new RichGraphEdge(
From: $"function:intermediate{i}",
To: "vuln:component",
Kind: "call",
Purl: "pkg:npm/vulnerable@1.0.0",
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null));
}
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: Array.Empty<RichGraphRoot>(),
Analyzer: new RichGraphAnalyzer("test", "1.0", null));
}
private static RichGraph CreateGraphWithDifferentEntrypoints()
{
var nodes = new List<RichGraphNode>
{
new(
Id: "entrypoint:http",
SymbolId: "handleRequest",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "entrypoint",
Display: "handleRequest()",
BuildId: null,
Evidence: null,
Attributes: new Dictionary<string, string> { ["http_method"] = "POST" },
SymbolDigest: null),
new(
Id: "entrypoint:main",
SymbolId: "main",
CodeId: null,
Purl: null,
Lang: "javascript",
Kind: "main",
Display: "main()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null),
new(
Id: "vuln:component",
SymbolId: "vulnerable",
CodeId: null,
Purl: "pkg:npm/vulnerable@1.0.0",
Lang: "javascript",
Kind: "function",
Display: "vulnerable()",
BuildId: null,
Evidence: null,
Attributes: null,
SymbolDigest: null)
};
var edges = new List<RichGraphEdge>
{
new(
From: "entrypoint:http",
To: "vuln:component",
Kind: "call",
Purl: "pkg:npm/vulnerable@1.0.0",
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null),
new(
From: "entrypoint:main",
To: "vuln:component",
Kind: "call",
Purl: "pkg:npm/vulnerable@1.0.0",
SymbolDigest: null,
Evidence: null,
Confidence: 0.9,
Candidates: null)
};
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: Array.Empty<RichGraphRoot>(),
Analyzer: new RichGraphAnalyzer("test", "1.0", null));
}
}