feat: Add PathViewer and RiskDriftCard components with templates and styles

- Implemented PathViewerComponent for visualizing reachability call paths.
- Added RiskDriftCardComponent to display reachability drift results.
- Created corresponding HTML templates and SCSS styles for both components.
- Introduced test fixtures for reachability analysis in JSON format.
- Enhanced user interaction with collapsible and expandable features in PathViewer.
- Included risk trend visualization and summary metrics in RiskDriftCard.
This commit is contained in:
master
2025-12-18 18:35:30 +02:00
parent 811f35cba7
commit 0dc71e760a
70 changed files with 8904 additions and 163 deletions

View File

@@ -206,15 +206,8 @@ public class PathExplanationServiceTests
private static RichGraph CreateSimpleGraph()
{
return new RichGraph
{
Schema = "stellaops.richgraph.v1",
Meta = new RichGraphMeta { Hash = "test-hash" },
Roots = new[]
{
new RichGraphRoot("entry-1", "runtime", null)
},
Nodes = new[]
return new RichGraph(
Nodes: new[]
{
new RichGraphNode(
Id: "entry-1",
@@ -241,21 +234,23 @@ public class PathExplanationServiceTests
Attributes: new Dictionary<string, string> { ["is_sink"] = "true" },
SymbolDigest: null)
},
Edges = new[]
Edges: new[]
{
new RichGraphEdge("entry-1", "sink-1", "call", null)
}
};
new RichGraphEdge("entry-1", "sink-1", "call", null, null, null, 1.0, null)
},
Roots: new[]
{
new RichGraphRoot("entry-1", "runtime", null)
},
Analyzer: new RichGraphAnalyzer("test", "1.0", null),
Schema: "stellaops.richgraph.v1"
);
}
private static RichGraph CreateGraphWithMultipleSinks()
{
return new RichGraph
{
Schema = "stellaops.richgraph.v1",
Meta = new RichGraphMeta { Hash = "test-hash" },
Roots = new[] { new RichGraphRoot("entry-1", "runtime", null) },
Nodes = new[]
return new RichGraph(
Nodes: new[]
{
new RichGraphNode("entry-1", "Handler", null, null, "java", "handler", null, null, null, null, null),
new RichGraphNode("sink-1", "Sink1", null, null, "java", "sink", null, null, null,
@@ -263,12 +258,15 @@ public class PathExplanationServiceTests
new RichGraphNode("sink-2", "Sink2", null, null, "java", "sink", null, null, null,
new Dictionary<string, string> { ["is_sink"] = "true" }, null)
},
Edges = new[]
Edges: new[]
{
new RichGraphEdge("entry-1", "sink-1", "call", null),
new RichGraphEdge("entry-1", "sink-2", "call", null)
}
};
new RichGraphEdge("entry-1", "sink-1", "call", null, null, null, 1.0, null),
new RichGraphEdge("entry-1", "sink-2", "call", null, null, null, 1.0, null)
},
Roots: new[] { new RichGraphRoot("entry-1", "runtime", null) },
Analyzer: new RichGraphAnalyzer("test", "1.0", null),
Schema: "stellaops.richgraph.v1"
);
}
private static RichGraph CreateGraphWithGates()
@@ -285,22 +283,21 @@ public class PathExplanationServiceTests
}
};
return new RichGraph
{
Schema = "stellaops.richgraph.v1",
Meta = new RichGraphMeta { Hash = "test-hash" },
Roots = new[] { new RichGraphRoot("entry-1", "runtime", null) },
Nodes = new[]
return new RichGraph(
Nodes: new[]
{
new RichGraphNode("entry-1", "Handler", null, null, "java", "handler", null, null, null, null, null),
new RichGraphNode("sink-1", "Sink", null, null, "java", "sink", null, null, null,
new Dictionary<string, string> { ["is_sink"] = "true" }, null)
},
Edges = new[]
Edges: new[]
{
new RichGraphEdge("entry-1", "sink-1", "call", gates)
}
};
new RichGraphEdge("entry-1", "sink-1", "call", null, null, null, 1.0, null, gates)
},
Roots: new[] { new RichGraphRoot("entry-1", "runtime", null) },
Analyzer: new RichGraphAnalyzer("test", "1.0", null),
Schema: "stellaops.richgraph.v1"
);
}
private static RichGraph CreateDeepGraph(int depth)
@@ -317,18 +314,17 @@ public class PathExplanationServiceTests
if (i > 0)
{
edges.Add(new RichGraphEdge($"node-{i - 1}", $"node-{i}", "call", null));
edges.Add(new RichGraphEdge($"node-{i - 1}", $"node-{i}", "call", null, null, null, 1.0, null));
}
}
return new RichGraph
{
Schema = "stellaops.richgraph.v1",
Meta = new RichGraphMeta { Hash = "test-hash" },
Roots = new[] { new RichGraphRoot("node-0", "runtime", null) },
Nodes = nodes,
Edges = edges
};
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: new[] { new RichGraphRoot("node-0", "runtime", null) },
Analyzer: new RichGraphAnalyzer("test", "1.0", null),
Schema: "stellaops.richgraph.v1"
);
}
private static RichGraph CreateGraphWithMultiplePaths(int pathCount)
@@ -344,17 +340,16 @@ public class PathExplanationServiceTests
{
nodes.Add(new RichGraphNode($"sink-{i}", $"Sink{i}", null, null, "java", "sink", null, null, null,
new Dictionary<string, string> { ["is_sink"] = "true" }, null));
edges.Add(new RichGraphEdge("entry-1", $"sink-{i}", "call", null));
edges.Add(new RichGraphEdge("entry-1", $"sink-{i}", "call", null, null, null, 1.0, null));
}
return new RichGraph
{
Schema = "stellaops.richgraph.v1",
Meta = new RichGraphMeta { Hash = "test-hash" },
Roots = new[] { new RichGraphRoot("entry-1", "runtime", null) },
Nodes = nodes,
Edges = edges
};
return new RichGraph(
Nodes: nodes,
Edges: edges,
Roots: new[] { new RichGraphRoot("entry-1", "runtime", null) },
Analyzer: new RichGraphAnalyzer("test", "1.0", null),
Schema: "stellaops.richgraph.v1"
);
}
private static ExplainedPath CreateTestPath()
@@ -364,7 +359,7 @@ public class PathExplanationServiceTests
PathId = "entry:sink:0",
SinkId = "sink-1",
SinkSymbol = "DB.query",
SinkCategory = SinkCategory.SqlRaw,
SinkCategory = Explanation.SinkCategory.SqlRaw,
EntrypointId = "entry-1",
EntrypointSymbol = "Handler.handle",
EntrypointType = EntrypointType.HttpEndpoint,
@@ -402,7 +397,7 @@ public class PathExplanationServiceTests
PathId = "entry:sink:0",
SinkId = "sink-1",
SinkSymbol = "DB.query",
SinkCategory = SinkCategory.SqlRaw,
SinkCategory = Explanation.SinkCategory.SqlRaw,
EntrypointId = "entry-1",
EntrypointSymbol = "Handler.handle",
EntrypointType = EntrypointType.HttpEndpoint,