CLI & API reference¶
Command line¶
revenant scenarios list built-in synthetic scenarios
revenant demo [--scenario NAME] run a scenario end-to-end, print report
revenant analyze PATH [PATH ...] analyse artefacts (OTRF JSON, .evtx, plaso
json_line/l2tcsv, Volatility dir, auth.log)
--kind K --format md|html|json|cypher --out FILE --pdf FILE
--ledger custody.sqlite --top N --include-noisy
revenant verify FILE|LEDGER.sqlite custody-ledger integrity check
revenant serve [--host --port] FastAPI + timeline/graph UI
HTTP API¶
When run with revenant serve (needs the api extra), the service exposes:
| Method & path | Purpose |
|---|---|
GET / |
single-page timeline + causal-graph UI |
GET /api/health |
liveness |
GET /api/scenarios |
built-in synthetic scenarios |
POST /api/cases/scenario/{name} |
analyse a synthetic scenario |
POST /api/cases/path |
analyse artefacts under the evidence root |
GET /api/cases |
list cases |
GET /api/cases/{id} |
stories, events, edges, indicators (JSON) |
GET /api/cases/{id}/report.md / .html |
court-style report |
GET /api/cases/{id}/cypher |
Neo4j export |
GET /api/cases/{id}/custody |
custody ledger + verification |
The service only reads evidence, only below REVENANT_EVIDENCE_ROOT, and binds to
localhost by default.
Python API¶
revenant.pipeline
¶
End-to-end orchestration.
Two entry points share one engine:
- :func:
run-- legacy v0.1 API over raw(kind, record)tuples (synthetic scenarios, hand-written fixtures). - :func:
analyze_paths/ :func:analyze_events-- real artefacts (OTRF JSON,.evtx, plaso, Volatility, auth.log) loaded by :mod:revenant.parsers.
Stages: ingest + integrity hashing -> custody ledger -> provenance graph -> cross-artefact fusion (corroboration) -> causal rules -> anti-forensics scan -> incident stories (ATT&CK-tagged, suspicion + confidence) and, for small graphs, v0.1 path chains. The custody ledger records every stage so every derived claim is traceable to the ingest records it depends on.
analyze_events(events, *, backend='auto', use_guids=True, story_config=None, ledger=None, chains=None)
¶
Run the full engine over already-normalized, hashed events.
analyze_paths(paths, *, kind=None, include_noisy=False, **kwargs)
¶
Load artefacts from disk (auto-detecting their kind) and analyse them.
Loader options (year and utc_offset_hours for auth.log, host
for Volatility output) are routed to the parsers; everything else goes to
:func:analyze_events.
run(records, *, backend='auto')
¶
v0.1 API: normalize raw (kind, record) pairs and analyse them.
revenant.models
¶
Typed contracts for REVENANT.
Every forensic fact flows through these models. The schema is deliberately
small and frozen-ish: an Event is an (actor, action, object, time) tuple
tied back to the raw artifact that produced it, plus an integrity hash. All
downstream reasoning (edges, chains, narratives) references events by id, so a
claim can always be traced to evidence.
SourceReliability
¶
Bases: str, Enum
Admiralty-code style source reliability (A=most reliable ... F=unknown).
EventType
¶
Bases: str, Enum
Normalized event categories used by the causal rule engine.
KillChainStage
¶
Bases: str, Enum
Lockheed-Martin cyber kill chain stages used for chain classification.
ConfidenceGrade
¶
Bases: str, Enum
Human-facing confidence bands for a reconstructed chain.
Event
¶
Bases: BaseModel
A single normalized forensic event.
event_id is stable and derived from content by the integrity layer.
integrity_hash binds the event to its raw source bytes.
canonical()
¶
Deterministic string used for hashing / stable ids.
CausalEdge
¶
Bases: BaseModel
A typed causal link inferred between two events.
ProvenanceChain
¶
Bases: BaseModel
An ordered candidate incident narrative (sequence of events).
CustodyRecord
¶
Bases: BaseModel
Append-only chain-of-custody ledger entry.
TamperingIndicator
¶
Bases: BaseModel
A cross-artifact inconsistency suggesting anti-forensics.
IncidentStory
¶
Bases: BaseModel
A reconstructed incident narrative: a causal subtree, not a single path.
Real process trees fan out (one payload spawns many children); a story keeps the whole subtree below a story root so the narrative reads like an analyst's write-up, with confidence and suspicion scored over it.
revenant.confidence
¶
Confidence scorer (ACH / Admiralty-inspired).
A chain's confidence blends four signals, each in [0,1]:
- reliability - mean source-reliability weight of its events
- corroboration - how many distinct source artifacts back the chain, counting cross-artefact corroborations found by fusion
- temporal_fit - mean temporal tightness of its causal edges
- edge_strength - mean rule confidence of its edges
Tampering indicators apply a multiplicative penalty. The result maps to a human-facing grade (LOW/MEDIUM/HIGH/CONFIRMED). Weights are explicit and documented so the score is defensible, not a black box.
revenant.integrity
¶
Integrity + chain-of-custody primitives.
Two guarantees:
- Every event gets a content-derived
integrity_hashand a stableevent_id(never trust an id supplied by an artifact). - An append-only, tamper-evident custody ledger: each record commits to the previous record's hash (a hash chain), so any silent edit or deletion breaks verification. The tool never mutates source artifacts.
CustodyLedger
¶
Append-only tamper-evident ledger of custody records.
verify()
¶
Recompute the hash chain; return False if any link is broken.
hash_event(event)
¶
Deterministic SHA-256 over the event's canonical form.
stable_event_id(event)
¶
A short, stable id derived from content (first 16 hex of the hash).
finalize_event(event)
¶
Return a copy of event with integrity_hash and event_id populated.
verify_event(event)
¶
True if the event's stored integrity_hash matches its content.
revenant.custody_store
¶
Persistent, append-only custody ledger (SQLite).
The spec calls for an append-only store (PostgreSQL). SQLite gives the same guarantees for a single examiner workstation with zero infrastructure:
BEFORE UPDATE/BEFORE DELETEtriggers abort any attempt to rewrite history through SQL;- every row still carries the hash chain from :class:
CustodyLedger, so an edit made around SQLite (hex-editing the file) is caught by :func:verify_store.
The same schema ports to PostgreSQL unchanged apart from the trigger syntax (see docs/adr/0005-custody-ledger.md).
revenant.export
¶
Exports: JSON (API/UI), Cypher (Neo4j) and an optional live Neo4j push.
The engine stays in-memory (networkx); Neo4j is a sink for analysts who want to explore the provenance graph in Neo4j Browser/Bloom. Export only the part of the graph that carries meaning -- events inside stories plus their edges -- so a 100k-event capture does not become a 100k-node dump.
to_dict(analysis, *, top=20)
¶
Compact JSON-able view: stories with their events and edges.
to_cypher(analysis, *, top=20)
¶
A self-contained Cypher script (cypher-shell < out.cypher).
push_neo4j(analysis, uri, user, password, *, top=20)
¶
Execute the Cypher export against a live Neo4j (optional neo4j driver).