From 2388a053ee6c25b5424fb523d2e386cd73dd8974 Mon Sep 17 00:00:00 2001 From: "Andoni A." <14891798+andoniaf@users.noreply.github.com> Date: Thu, 8 Jan 2026 18:18:44 +0100 Subject: [PATCH] fix(attack-paths): highlight single path upstream instead of all paths Changed upstream traversal to follow only one parent at each level instead of all parents. This prevents the entire graph from lighting up when selecting a node that has multiple ancestors with many children. - Upstream: now uses find() to get first parent only - Downstream: unchanged, still highlights all descendants --- .../_components/graph/attack-path-graph.tsx | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/ui/app/(prowler)/attack-paths/(workflow)/query-builder/_components/graph/attack-path-graph.tsx b/ui/app/(prowler)/attack-paths/(workflow)/query-builder/_components/graph/attack-path-graph.tsx index 1620c71e1a..d9c47d0542 100644 --- a/ui/app/(prowler)/attack-paths/(workflow)/query-builder/_components/graph/attack-path-graph.tsx +++ b/ui/app/(prowler)/attack-paths/(workflow)/query-builder/_components/graph/attack-path-graph.tsx @@ -91,7 +91,9 @@ const AttackPathGraphComponent = forwardRef< selectedNodeIdRef.current = selectedNodeId ?? null; }, [selectedNodeId]); - // Helper function to find all edges in the path from a given node + // Helper function to find edges in the path from a given node + // Upstream: follows only ONE parent path (first parent at each level) to avoid lighting up siblings + // Downstream: follows ALL children recursively const getPathEdges = ( nodeId: string, edges: Array<{ sourceId: string; targetId: string }>, @@ -99,20 +101,21 @@ const AttackPathGraphComponent = forwardRef< const pathEdgeIds = new Set(); const visitedNodes = new Set(); - // Traverse upstream (find all sources leading to this node) + // Traverse upstream - only follow ONE parent at each level (first found) + // This creates a single path to the root, not all paths const traverseUpstream = (currentNodeId: string) => { if (visitedNodes.has(`up-${currentNodeId}`)) return; visitedNodes.add(`up-${currentNodeId}`); - edges.forEach((edge) => { - if (edge.targetId === currentNodeId) { - pathEdgeIds.add(`${edge.sourceId}-${edge.targetId}`); - traverseUpstream(edge.sourceId); - } - }); + // Find the first parent edge only + const parentEdge = edges.find((edge) => edge.targetId === currentNodeId); + if (parentEdge) { + pathEdgeIds.add(`${parentEdge.sourceId}-${parentEdge.targetId}`); + traverseUpstream(parentEdge.sourceId); + } }; - // Traverse downstream (find all targets from this node) + // Traverse downstream (find ALL targets from this node) const traverseDownstream = (currentNodeId: string) => { if (visitedNodes.has(`down-${currentNodeId}`)) return; visitedNodes.add(`down-${currentNodeId}`);