Objective
After each scan, populate the graph with resource nodes from the
InventorySnapshot and infer edges between them with evidence provenance.
Depends on: #331
Scope
Node population (scanner/graph/node_service.py)
- Upsert graph_nodes from snapshot.resources keyed on (tenant_id, resource_id)
- Link each finding to its node via finding_graph_nodes
- Run as a post-scan step; failure logs but does not fail the scan
Edge detection (scanner/graph/edge_detector.py)
- EdgeDetector base class: detect(snapshot, nodes) -> list[GraphEdge]
- Initial detectors:
- NsgToSubnet (PROTECTS)
- SubnetToResource (MEMBER_OF)
- PublicIpToResource (EXPOSES)
- IdentityToResource (HAS_IDENTITY)
- StoragePrivateEndpoint (REACHABLE_VIA)
- Confidence: ARG-confirmed 1.0, inferred from properties 0.8,
cross-referenced 0.6
- Upsert edges on each scan; no duplicates
Test plan
Objective
After each scan, populate the graph with resource nodes from the
InventorySnapshot and infer edges between them with evidence provenance.
Depends on: #331
Scope
Node population (scanner/graph/node_service.py)
Edge detection (scanner/graph/edge_detector.py)
cross-referenced 0.6
Test plan