-
-
Notifications
You must be signed in to change notification settings - Fork 0
Knowledge Map
The Graph tab on a case renders that case as a knowledge map: assets, IOCs, notes and evidence as nodes, with edges for the relationships between them. A layer filter in the toolbar turns each object type on and off.
Upstream, this tab drew only assets and IOCs, and connected two objects only when they appeared on the same timeline event. IRIS-NG adds note and evidence layers plus the direct object-to-object links held in the M2M link tables.
| Layer | Node style | Source |
|---|---|---|
| Assets | Icon (compromise-aware) | case_assets |
| IOCs | Virus icon | ioc |
| Notes | Violet box | ioc_note_link |
| Evidence | Amber box | evidence_asset_link |
Toggling a layer hides its nodes and every edge touching them. Filtering runs
client-side against the payload already in memory, so toggles are instant and
never re-hit the API. Selections persist per browser in localStorage
(irisGraphLayers), and all layers default to on.
The toolbar also shows a live N nodes / N links readout for the current
selection. The panel is hidden below 1200px viewport width, where the canvas
needs the space more than the controls do.
Every edge carries a kind:
kind |
Meaning | Style |
|---|---|---|
event |
The two objects appear on the same timeline event | Solid (dashed if either end is an IOC) |
direct |
A row in an M2M link table joins them | Dashed, layer-coloured |
direct edges come from three tables:
| Table | Edge |
|---|---|
ioc_note_link |
Note → IOC (provenance: which note produced this IOC) |
evidence_asset_link |
Evidence → Asset |
ioc_asset_link |
IOC → Asset |
Direct links matter because event co-occurrence alone is incomplete: two objects that are genuinely linked but never share a timeline event previously appeared unconnected on the graph.
Only linked notes and evidence become nodes. A note that sources no IOC, or an evidence item linked to no asset, is not drawn — isolated nodes are noise on a force-directed layout.
Redundant direct edges are suppressed. When a timeline event already
connects two nodes, a direct link between the same pair is dropped rather than
drawn as a second parallel line. No connection is lost: kind is not a filter
dimension, so a suppressed edge can never be the only thing joining two visible
nodes.
The Notes layer is IOC-centric by construction. ioc_note_link is the only
note link table, so notes attach to IOCs and nothing else. A note that discusses
an asset or an evidence item has no edge to it.
Notes and evidence only appear once the underlying links exist:
-
IOC ↔ Note — created automatically when the AI IOC extractor's
+ addflow promotes a suggestion from a note. For cases predating that feature, runbackfill_ioc_note_links.py, which refangs defanged values before matching. - Evidence ↔ Asset — set via the Related Evidence picker on the asset modal, or the inverse chips on the edit-evidence modal.
- IOC ↔ Asset — created by "push IOCs to assets" and by working-timeline promotion.
GET /case/graph/getdata?cid=<case_id>
Returns the legacy envelope ({status, message, data}) with data.nodes,
data.edges and data.dates. The IRIS-NG additions are purely additive, so
existing consumers are unaffected:
Node id prefixes: a asset, b IOC, n note, e evidence.
| Concern | Location |
|---|---|
| Endpoint | source/app/blueprints/rest/case/case_graphs_routes.py |
| Link queries | source/app/datamgmt/case/case_graph_db.py |
| Renderer + filter | ui/public/assets/js/iris/case.graph.js |
| Toolbar + styles | source/app/blueprints/pages/case/templates/case_graph.html |
case.graph.js has no import statements, so it lives in ui/public/ and is
copied verbatim by Vite — see
Development Guide → Import-free JS belongs in ui/public/.
Deploy it with docker cp plus a browser hard-reload; template changes need
docker restart iriswebapp_app because Jinja auto-reload is off.
{ "nodes": [ { "id": "a14", "layer": "asset", "label": "WE-WKS-4471", "shape": "image", ... }, { "id": "b25", "layer": "ioc", "label": "203.0.113.47", ... }, { "id": "n7", "layer": "note", "label": "Initial summary", "shape": "box", ... }, { "id": "e3", "layer": "evidence", "label": "MS Sentinel logs", "shape": "box", ... } ], "edges": [ { "from": "a14", "to": "b26", "kind": "event" }, { "from": "n7", "to": "b25", "kind": "direct" } ] }