Skip to content

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:

  1. Every event gets a content-derived integrity_hash and a stable event_id (never trust an id supplied by an artifact).
  2. 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 DELETE triggers 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).

append_ledger(ledger, path)

Append ledger records not yet in the store. Returns rows written.

The store must be a prefix of ledger (same hashes); anything else means the two histories diverged and is refused.

verify_store(path)

Recompute the hash chain of a stored ledger.

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).