feat(attack-paths): grouped template-graph view with attack outcomes#11357
Draft
HugoPBrito wants to merge 4 commits into
Draft
feat(attack-paths): grouped template-graph view with attack outcomes#11357HugoPBrito wants to merge 4 commits into
HugoPBrito wants to merge 4 commits into
Conversation
- Drop account/root-labeled nodes (AWSAccount, AzureSubscription, AzureTenant, GCPProject, KubernetesCluster, GitHubAccount) and their relationships from the serialized attack-paths graph. The account stays the Cypher MATCH anchor; tenant/provider isolation is unaffected. - Add AttackPathsQueryOutcome (label, description, severity) and an outcome field on AttackPathsQueryDefinition. Assign outcomes to every real attack-path query by id pattern in aws.py (privesc-passrole and code-exec to 'Code execution', IAM/STS privesc to 'Privilege escalation', internet-exposed chain to 'Data exfiltration'). The 11 inventory queries keep outcome=None. - execute_query attaches outcome to the run-query response; expose it via new AttackPathsQueryOutcomeSerializer in AttackPathsQuerySerializer and AttackPathsQueryResultSerializer (allow_null). - attack_paths_queries action filters the catalog to queries with an outcome (78 -> 67 surfaced; 11 inventory hidden). - Existing tests that used AWSAccount as a generic node updated to AWSRole; new tests cover account stripping and outcome passthrough.
Redesigns the Attack Paths graph around the structure of the attack: - New _lib/template-graph.ts groups concrete nodes by resource type into one synthetic node per type (with a count badge), dedupes inter-group edges, drops intra-group self-loops, and appends a terminal Outcome node wired from the sink representatives. Account and finding nodes are filtered out of this structural view. - _lib/layout.ts adds 'attackGroup' and 'outcome' node types and a MarkerType.ArrowClosed markerEnd on every edge so attack direction is explicit. 'attackGroup' is intentionally named off the reserved React Flow 'group' type, which otherwise paints a default gray container behind the node. - New GroupNode (stacked-card visual, type icon, count badge, click-to-expand) and OutcomeNode (severity-colored terminal with Crosshair) components, registered in NODE_TYPES. - useGraphStore gains templateSource, outcome, expandedTypes and toggleExpandedType; the rendered graph is the collapsed template, recomputed via buildTemplateGraph on every state change. - attack-paths-page handleNodeClick: grouped type -> expand; expanded concrete resource -> collapse its type; outcome node is inert. A key based on expandedTypes forces React Flow to refit on expansion. Banner copy updated. - graph-legend.tsx skips the outcome marker label so the legend does not list it as a resource type. - Unit tests for buildTemplateGraph (grouping, edge dedup, expand, sink->outcome wiring, finding/account drop, empty input) and for the new edge markerEnd in layoutWithDagre.
The browser E2E suite asserts the pre-redesign default view (finding nodes rendered eagerly in the default graph, click-to-filter from findings). The new template-graph view replaces that default with a grouped structural view that excludes findings, so the existing flows do not apply. Quarantined with describe.skip until the suite is rewritten for the new UX.
Contributor
|
✅ Conflict Markers Resolved All conflict markers have been successfully resolved in this pull request. |
Contributor
|
Please add an entry to the corresponding |
Document the API (account stripping + outcome metadata + filtered catalog) and UI (grouped template view with expand-on-click, outcome node, arrowheads) changes under the current API/UI version sections, referencing PR #11357.
Contributor
🔒 Container Security ScanImage: 📊 Vulnerability Summary
11 package(s) affected
|
Contributor
🔒 Container Security ScanImage: 📊 Vulnerability Summary
2 package(s) affected
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
The Attack Paths graph renders every concrete resource individually, anchored to a hub
AWSAccountnode that fans out to everything. This adds noise (the account is implicit), makes the graph hard to read at first sight, has no arrowheads (direction is only implied by layout), and does not represent the outcome of the attack chain (e.g. "code execution as a privileged role").This PR redesigns the visualization around the structure of the attack instead of the concrete inventory.
Description
API (
api/src/backend/api/attack_paths/)_serialize_graphdrops account/root-labeled nodes (AWSAccount,AzureSubscription,AzureTenant,GCPProject,KubernetesCluster,GitHubAccount) and their relationships. The account is still the CypherMATCHanchor, so tenant/provider isolation is unaffected.AttackPathsQueryOutcomedataclass (label / description / severity). Outcomes are assigned by query id pattern inaws.py: privesc-passrole and code-exec paths → "Code execution", IAM/STS privesc → "Privilege escalation", internet-exposed chain → "Data exfiltration". Inventory queries keepoutcome=None.execute_queryreturnsoutcomealongsidenodes/relationships.AttackPathsQueryOutcomeSerializer;outcome(allow_null) added toAttackPathsQuerySerializerandAttackPathsQueryResultSerializer.attack_paths_queriesaction filters the catalog to queries withoutcome is not None(78 → 67 surfaced; 11 inventory hidden).UI (
ui/app/(prowler)/attack-paths/(workflow)/query-builder/)_lib/template-graph.ts(buildTemplateGraph(data, expandedTypes, outcome)): groups concrete nodes by resource type into one synthetic node each, dedupes inter-group edges, drops intra-group self-loops, and appends an Outcome node wired from the sink representatives. Account and finding nodes are filtered out of this structural view._lib/layout.ts: new node typesattackGroup(renamed off the reserved React Flowgrouptype that paints a default gray container) andoutcome;markerEnd: ArrowClosedon every edge.GroupNode(stacked-card visual + count badge + "click to expand") andOutcomeNode(terminal node colored by severity).useGraphStoregainstemplateSource,outcome,expandedTypesandtoggleExpandedType; the default rendered graph is the collapsed template, derived viabuildTemplateGraphon every state change.attack-paths-page.tsx: clicking a group expands its type; clicking an expanded concrete resource collapses its type back; outcome nodes are inert. Akeybased onexpandedTypesforces React Flow to refit on expansion. Banner copy updated to reflect the new UX.graph-legend.tsxskips the outcome marker label so the legend does not list it as a resource type.Known limitations / follow-ups
attack-paths-page.browser.test.tsxis quarantined withdescribe = describeBase.skipbecause it asserts the pre-redesign default view (finding nodes rendered eagerly, click-to-filter from findings). Rewriting it for the new UX is a follow-up.Steps to review
aws-rds-instances,aws-iam-statements-*,aws-*-internet-exposed,aws-public-ip-resource-lookup).AWSAccountnode, the graph reads left to right with arrowheads, one node per resource type with a count badge, and a terminal Outcome node ("Code execution"). Inventory queries (if you call them directly via API) still render but withoutcome: null.AWS Role(or any other) group to expand it into the individual roles; click any of those concrete nodes to collapse the group back.pytest api/tests/test_attack_paths.py(43 tests). UI:pnpm vitest run _lib/template-graph.test.ts _lib/layout.test.ts(18 tests).Checklist
buildTemplateGraph,markerEnd, account stripping, and outcome passthrough.License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.