Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Created CycloneDX and SPDX SBOM files for both reachable and unreachable images. - Added symbols.json detailing function entry and sink points in the WordPress code. - Included runtime traces for function calls in both reachable and unreachable scenarios. - Developed OpenVEX files indicating vulnerability status and justification for both cases. - Updated README for evaluator harness to guide integration with scanner output.
122 lines
4.2 KiB
C#
122 lines
4.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
|
|
namespace StellaOps.Scanner.Reachability;
|
|
|
|
public sealed class ReachabilityGraphBuilder
|
|
{
|
|
private const string GraphSchemaVersion = "1.0";
|
|
private readonly HashSet<string> nodes = new(StringComparer.Ordinal);
|
|
private readonly HashSet<ReachabilityEdge> edges = new();
|
|
|
|
public ReachabilityGraphBuilder AddNode(string symbolId)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(symbolId))
|
|
{
|
|
nodes.Add(symbolId.Trim());
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public ReachabilityGraphBuilder AddEdge(string from, string to, string kind = "call")
|
|
{
|
|
if (string.IsNullOrWhiteSpace(from) || string.IsNullOrWhiteSpace(to))
|
|
{
|
|
return this;
|
|
}
|
|
|
|
var edge = new ReachabilityEdge(from.Trim(), to.Trim(), string.IsNullOrWhiteSpace(kind) ? "call" : kind.Trim());
|
|
edges.Add(edge);
|
|
nodes.Add(edge.From);
|
|
nodes.Add(edge.To);
|
|
return this;
|
|
}
|
|
|
|
public string BuildJson(bool indented = true)
|
|
{
|
|
var payload = new ReachabilityGraphPayload
|
|
{
|
|
SchemaVersion = GraphSchemaVersion,
|
|
Nodes = nodes.Select(id => new ReachabilityNode(id)).ToList(),
|
|
Edges = edges.Select(edge => new ReachabilityEdgePayload(edge.From, edge.To, edge.Kind)).ToList()
|
|
};
|
|
|
|
var options = new JsonSerializerOptions
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = indented
|
|
};
|
|
|
|
return JsonSerializer.Serialize(payload, options);
|
|
}
|
|
|
|
public static ReachabilityGraphBuilder FromFixture(string variantPath)
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(variantPath);
|
|
var builder = new ReachabilityGraphBuilder();
|
|
|
|
foreach (var fileName in new[] { "callgraph.static.json", "callgraph.framework.json" })
|
|
{
|
|
var path = Path.Combine(variantPath, fileName);
|
|
if (!File.Exists(path))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
using var stream = File.OpenRead(path);
|
|
using var document = JsonDocument.Parse(stream);
|
|
var root = document.RootElement;
|
|
|
|
if (root.TryGetProperty("nodes", out var nodesElement) && nodesElement.ValueKind == JsonValueKind.Array)
|
|
{
|
|
foreach (var node in nodesElement.EnumerateArray())
|
|
{
|
|
var sid = node.TryGetProperty("sid", out var sidElement)
|
|
? sidElement.GetString()
|
|
: node.GetProperty("id").GetString();
|
|
builder.AddNode(sid ?? string.Empty);
|
|
}
|
|
}
|
|
|
|
if (root.TryGetProperty("edges", out var edgesElement) && edgesElement.ValueKind == JsonValueKind.Array)
|
|
{
|
|
foreach (var edge in edgesElement.EnumerateArray())
|
|
{
|
|
var from = edge.TryGetProperty("from", out var fromEl)
|
|
? fromEl.GetString()
|
|
: edge.GetProperty("source").GetString();
|
|
var to = edge.TryGetProperty("to", out var toEl)
|
|
? toEl.GetString()
|
|
: edge.GetProperty("target").GetString();
|
|
var kind = edge.TryGetProperty("kind", out var kindEl)
|
|
? kindEl.GetString()
|
|
: edge.TryGetProperty("type", out var typeEl)
|
|
? typeEl.GetString()
|
|
: "call";
|
|
|
|
builder.AddEdge(from ?? string.Empty, to ?? string.Empty, kind ?? "call");
|
|
}
|
|
}
|
|
}
|
|
|
|
return builder;
|
|
}
|
|
|
|
private sealed record ReachabilityEdge(string From, string To, string Kind);
|
|
|
|
private sealed record ReachabilityNode(string Sid);
|
|
|
|
private sealed record ReachabilityEdgePayload(string From, string To, string Kind);
|
|
|
|
private sealed record ReachabilityGraphPayload
|
|
{
|
|
public string SchemaVersion { get; set; } = GraphSchemaVersion;
|
|
public List<ReachabilityNode> Nodes { get; set; } = new();
|
|
public List<ReachabilityEdgePayload> Edges { get; set; } = new();
|
|
}
|
|
}
|