Graph
The graph is the data structure behind Puck’s blast-radius map — a relationship view built from findings and agent results. Hosts, credentials, identities, services, and the connections between them, with edges that weaken over time. The console renders it as the blast-radius map; the API surface (/v1/graph/*) calls it the graph because it is one (nodes + edges + freshness windows). Both names refer to the same thing.
Why it exists
Findings are atomic. A finding says “this binary was observed on this host.” The graph answers the follow-up questions: which other hosts have a relationship with that host? What credentials were observed alongside it? Which network connections did it make?
When you’re investigating lateral movement, a list of findings is hard to navigate. The graph lets you focus on a node and walk its neighbours — pivoting from an IOC to the hosts it touched, from a host to the credentials it exposed, from a credential to the identities that own it.
It also accumulates evidence over time rather than replacing it. Each new investigation that confirms a relationship re-confirms its edge. Relationships that aren’t re-confirmed decay.
How it works
The graph has two primitive types:
Nodes represent entities — a host, a credential, an IAM role, a network service, a file hash. Each node has a node_type (for example host, credential, iam-role, service), an external_id that identifies it within that type (for example agent:abc123 or iam-role:arn:aws:iam::123456:role/deploy), and a set of freeform attributes.
Edges represent relationships between nodes — “this host made a network connection to this service,” “this credential was observed on this host,” “this process wrote this file.” Each edge carries full provenance: which agent confirmed it, under which plan, at what confidence, and when it was last seen.
Half-life decay: Edges have an expires_at timestamp computed from when they were confirmed. An edge that hasn’t been re-confirmed by a subsequent investigation eventually expires. This prevents the graph from accumulating stale relationships indefinitely — a host that stopped communicating with a service six months ago should eventually lose that edge.
When a new investigation confirms an existing relationship, the edge is upserted: confirmed_at and expires_at are updated, confidence is refreshed. The node’s last_seen_at is also updated.
flowchart LR H1[Host: eng-laptop-07] -->|credential_observed| C1[Credential: OPENAI_API_KEY] H1 -->|network_connection| S1[Service: api.openai.com:443] H1 -->|process_running| P1[Process: ollama] P1 -->|network_connection| S2[Service: 10.0.1.44:11434]When you’d touch it
The Console → Graph page gives you a visual interface for the graph. You can search for a specific entity by type and identifier, focus on a node, and walk its neighbours by edge type.
The most common patterns:
Pivot from an IOC. You have a file hash or IP address from a threat intel feed. Search the graph for that indicator and see which hosts and processes are connected to it.
Blast-radius investigation. A host is confirmed compromised. Focus on it in the graph and walk outbound edges: which credentials were observed on it? Which services did it connect to? Which other hosts share those connections?
Lateral movement tracing. Starting from a known entry point, follow network connection edges to see which services it reached, then follow from those services to see which other hosts have established connections to the same targets.
The Graph API gives you programmatic access to node and subgraph queries if you want to pull graph data into your own tooling or SIEM.