Skip to content

CLI & API reference

Command line

revenant scenarios                          list built-in synthetic scenarios
revenant demo [--scenario NAME] [--top N]   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,
                                            auditd, ATLAS preprocessed logs)
     --kind otrf|evtx|plaso|volatility|authlog|auditd|atlas  --host H
     --format md|html|json|cypher  --out FILE  --pdf FILE
     --ledger case.sqlite  --top N  --include-noisy
revenant verify FILE|LEDGER.sqlite          custody-ledger integrity check (read-only)
     --expect-head HASH  --expect-count N   external anchors (detect truncation/rewrite)
revenant --version
revenant serve [--host H] [--port P] [--allow-remote]
                                            FastAPI + timeline/graph UI; a non-loopback
                                            --host is refused without --allow-remote

--ledger persists the custody ledger to a new SQLite store; a store that already holds another case's ledger is refused (exit 2) before any report is written. ```

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:

  • run -- legacy v0.1 API over raw (kind, record) tuples (synthetic scenarios, hand-written fixtures).
  • analyze_paths / analyze_events -- real artefacts (OTRF JSON, .evtx, plaso, Volatility, auth.log) loaded by 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.

file_sha256(path)

Return the SHA-256 hex digest of a file, read in 1 MiB chunks.

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

weight property

Return the reliability weight of this evidence source class.

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.

from_score(score) classmethod

Map a numeric confidence score to a grade using the fixed cut-offs.

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 (Admiralty-inspired source reliability).

A chain's confidence is a weighted sum of 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 and grade cut-offs are explicit, hand-set and documented so the score is defensible, not a black box. Only the per-rule edge confidences feeding edge_strength are calibrated against ground truth; the story score itself is not a calibrated probability.

ConfidenceBreakdown dataclass

Every term of a story/chain confidence score, for the report and the UI.

Attributes:

Name Type Description
reliability, corroboration, temporal_fit, edge_strength

The four weighted terms, each in [0, 1].

penalty float

Multiplicative tampering penalty (1.0 = none, floored at 0.5).

score float

penalty * sum(WEIGHTS[k] * term_k).

grade ConfidenceGrade

score mapped through the hand-set cut-offs.

as_dict()

Return the fields as a JSON-serialisable dict.

score_chain(chain, graph)

Score a chain or story against the provenance graph it came from.

Parameters:

Name Type Description Default
chain ProvenanceChain | IncidentStory

A path-view chain or an incident story (its event_ids, edges and tampering_flags are read).

required
graph ProvenanceGraph

The graph holding the events, used for reliability and corroborating sources.

required

Returns:

Type Description
ConfidenceBreakdown

All terms plus the final score and grade.

apply_score(chain, graph)

Compute score_chain and store the score and grade on chain (returned).

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.

records property

Return a copy of the custody records in ledger order.

append(action, digest, *, event_id=None, artifact=None, when=None)

Append a hash-chained custody record.

Parameters:

Name Type Description Default
action str

What happened (for example ingest).

required
digest str

SHA-256 of the subject.

required
event_id str

What the record refers to.

None
artifact str

What the record refers to.

None
when datetime

Record time; defaults to now (UTC).

None

Returns:

Type Description
CustodyRecord

The new record, chained to the previous one.

record_ingest(event)

Append an ingest record for a finalised event.

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 CustodyLedger, so an edit made around SQLite (hex-editing the file) is caught by 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.

missing_triggers(path)

Append-only triggers absent from the store (a dropped trigger is a tamper sign).

load_ledger(path)

Load a stored ledger read-only. Raises FileNotFoundError for a missing path.

verify_store(path, *, expect_head=None, expect_count=None)

Recompute the hash chain of a stored ledger.

The internal chain alone cannot reveal a truncated tail or a full rewrite; pass the head hash / record count printed in the report (an external anchor) to detect those too. Missing append-only triggers fail verification.

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.

story_event_ids(analysis, top=None)

Return the unique event ids of the top stories, in first-seen order.

to_dict(analysis, *, top=20, include_all_events=False, max_events=5000)

JSON-able view of an analysis: stories with their events and edges.

Parameters:

Name Type Description Default
analysis Analysis

Result of revenant.pipeline.run or revenant.pipeline.analyze_paths.

required
top int

Number of ranked stories to include.

20
include_all_events bool

Also include events outside any story (up to max_events), so a case with no story still has a timeline. The path-view chains are always included.

False

to_json(analysis, *, top=20)

Serialise an analysis to indented JSON, limited to the top stories.

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