Files
git.stella-ops.org/src/Scanner/__Tests/StellaOps.Scanner.Reachability.Tests/RichGraphWriterTests.cs
StellaOps Bot 28823a8960 save progress
2025-12-18 09:10:36 +02:00

112 lines
4.0 KiB
C#

using System.IO;
using System.Threading.Tasks;
using StellaOps.Cryptography;
using StellaOps.Scanner.Reachability;
using StellaOps.Scanner.Reachability.Gates;
using Xunit;
namespace StellaOps.Scanner.Reachability.Tests;
public class RichGraphWriterTests
{
[Fact]
public async Task WritesCanonicalGraphAndMeta()
{
var writer = new RichGraphWriter(CryptoHashFactory.CreateDefault());
using var temp = new TempDir();
var union = new ReachabilityUnionGraph(
Nodes: new[]
{
new ReachabilityUnionNode("sym:dotnet:B", "dotnet", "method", "B"),
new ReachabilityUnionNode("sym:dotnet:A", "dotnet", "method", "A")
},
Edges: new[]
{
new ReachabilityUnionEdge("sym:dotnet:A", "sym:dotnet:B", "call", "high")
});
var rich = RichGraphBuilder.FromUnion(union, "test-analyzer", "1.0.0");
var result = await writer.WriteAsync(rich, temp.Path, "analysis-1");
Assert.True(File.Exists(result.GraphPath));
Assert.True(File.Exists(result.MetaPath));
var json = await File.ReadAllTextAsync(result.GraphPath);
Assert.Contains("richgraph-v1", json);
Assert.Contains(":", result.GraphHash); // hash format: algorithm:digest
Assert.Equal(2, result.NodeCount);
Assert.Equal(1, result.EdgeCount);
}
[Fact]
public async Task CarriesSymbolMetadataToRichGraph()
{
var writer = new RichGraphWriter(CryptoHashFactory.CreateDefault());
using var temp = new TempDir();
var union = new ReachabilityUnionGraph(
Nodes: new[]
{
new ReachabilityUnionNode(
"sym:binary:target",
"binary",
"function",
"ssl_read",
CodeBlockHash: "sha256:blockhash",
Symbol: new ReachabilitySymbol("_Zssl_read", "ssl_read", "DWARF", 0.9))
},
Edges: Array.Empty<ReachabilityUnionEdge>());
var rich = RichGraphBuilder.FromUnion(union, "test-analyzer", "1.0.0");
var result = await writer.WriteAsync(rich, temp.Path, "analysis-symbol-rich");
var json = await File.ReadAllTextAsync(result.GraphPath);
Assert.Contains("\"code_block_hash\":\"sha256:blockhash\"", json);
Assert.Contains("\"symbol\":{\"mangled\":\"_Zssl_read\",\"demangled\":\"ssl_read\",\"source\":\"DWARF\",\"confidence\":0.9}", json);
}
[Fact]
public async Task WritesGatesOnEdgesWhenPresent()
{
var writer = new RichGraphWriter(CryptoHashFactory.CreateDefault());
using var temp = new TempDir();
var union = new ReachabilityUnionGraph(
Nodes: new[]
{
new ReachabilityUnionNode("sym:dotnet:B", "dotnet", "method", "B"),
new ReachabilityUnionNode("sym:dotnet:A", "dotnet", "method", "A")
},
Edges: new[]
{
new ReachabilityUnionEdge("sym:dotnet:A", "sym:dotnet:B", "call", "high")
});
var rich = RichGraphBuilder.FromUnion(union, "test-analyzer", "1.0.0");
var gate = new DetectedGate
{
Type = GateType.AuthRequired,
Detail = "Auth required: ASP.NET Core Authorize attribute",
GuardSymbol = "sym:dotnet:B",
Confidence = 0.95,
DetectionMethod = "annotation:\\[Authorize\\]"
};
rich = rich with
{
Edges = new[]
{
rich.Edges[0] with { Gates = new[] { gate }, GateMultiplierBps = 3000 }
}
};
var result = await writer.WriteAsync(rich, temp.Path, "analysis-gates");
var json = await File.ReadAllTextAsync(result.GraphPath);
Assert.Contains("\"gate_multiplier_bps\":3000", json);
Assert.Contains("\"gates\":[", json);
Assert.Contains("\"type\":\"authRequired\"", json);
Assert.Contains("\"guard_symbol\":\"sym:dotnet:B\"", json);
}
}