Evidence
Documentation

Version Latest

Verify offline

Use keystone-audit-verify to export the audit chain and prove it intact without network access, including the cold tier and an organisation's own segments.

keystone-audit-verify is a standalone verifier shipped with each release. It checks an exported audit chain cryptographically without connecting to any Govern server, so an air-gapped operator or an external auditor can run it on a machine with no network.

Commands

CommandWhat it does
exportExports the audit chain, Merkle tree heads and public key from a live database
verifyVerifies an exported chain offline
coldVerifies cold tier segments (Parquet objects) offline, alone or joined to a hot export
versionPrints the version

Exit codes

CodeMeaning
0Every verification passed
1Fatal error: the verification could not run
2Verification failed: the chain was tampered with or a signature is invalid
3An agent export cannot be verified (pseudonymised entries)

Export and verify the hot tier

The export reads the instance-wide chain and the signing keys across organisations, so it connects as the keystone_platform role, not as the runtime role.

keystone-audit-verify export --db "$DATABASE_PLATFORM_URL" --from 2026-01-01 --to 2026-09-30

keystone-audit-verify verify --chain audit_chain.json --tree-heads audit_tree_heads.json \
  --public-key keystone_audit.pub --output report.json

Export flags

FlagMeaning
--db URLPostgreSQL URL of the keystone_platform role, or set DATABASE_PLATFORM_URL
--org ORG_IDOne organisation; empty for all
--from DATE, --to DATEWindow, YYYY-MM-DD
--out-chain FILEDefault audit_chain.json
--out-tree-heads FILEDefault audit_tree_heads.json
--out-public-key FILEDefault keystone_audit.pub

Verify flags

FlagMeaning
--chain FILEExported chain (required). A signed agent export is detected and verified as one
--tree-heads FILEMerkle tree heads; enables Merkle verification
--public-key FILEEd25519 public key for Merkle and timestamp signatures
--hmac-key KEYNI_AUTH_AUDIT_HMAC_KEY, to re-derive every entry hash
--output FILEWrite the report as JSON
--format json|textOutput format (default text)
--strictFail if any optional check cannot be performed

Without --hmac-key the verifier checks links, sequence numbers and signatures; with it, it also recomputes every entry hash. The HMAC key is a secret of the operator: give it to an auditor only under your own procedure.

The verifier checks continuity per organisation chain and lane, from each chain's genesis, which commits to the end of the ledger written before per-organisation chains existed.

Verify the cold tier

When audit tiering is on, entries older than the hot window are in the audit bucket. Verify the whole ledger, both tiers, end to end:

aws s3 sync s3://<audit bucket>/audit/<cell> ./audit-bucket
keystone-audit-verify export --db "$DATABASE_PLATFORM_URL" --from 2026-01-01 --to 2100-01-01
keystone-audit-verify cold --dir ./audit-bucket --keys keystone-audit-keys.json \
  --hmac-key "$NI_AUTH_AUDIT_HMAC_KEY" --hot audit_chain.json

keystone-audit-keys.json is the key set published at /.well-known/keystone-audit-keys.json.

For every segment the verifier checks the manifest signature, the spine (SHA-256, id range, every chain link, first and last hashes) and every object (SHA-256, each row present in the spine at its id, one organisation per object, the objects together covering the spine), and with the HMAC key re-derives every entry hash. Across segments it checks sequence numbers, the manifest chain and the link from each segment to the next. A platform verification requires segment 1: a missing first segment fails.

With --hot, the hot export is checked against the segments: entries above the last segment must continue its chain link by link. A missing, reordered or altered entry, or a gap at the boundary between the tiers, fails. After tiering, the hot export has gaps where entries moved; verify it with cold --hot, not with verify alone.

Cold flags

FlagMeaning
--dir DIRThe segments as stored in the bucket, or an organisation's download of its own segments (required)
--keys FILEThe audit signing key set
--hmac-key KEYRe-derive every entry hash
--org ORG_IDVerify one organisation's objects and their completeness
--platform-entriesVerify the platform entries' objects
--hot FILEA hot tier export of every organisation
--output FILE, --format json|textReport
--strictFail without the key set or the HMAC key (and, for a platform verification, without --hot)

An organisation verifies its own entries

An organisation does not need the operator's HMAC key or anyone else's data to prove its own cold entries complete and in the chain. With audit:read:

# list the organisation's sealed segments
curl -H "Authorization: Bearer $TOKEN" https://<your Govern host>/api/v1/audit-logs/cold-segments

# download one segment as a tar: manifest, signature, spine and the organisation's object
curl -H "Authorization: Bearer $TOKEN" -o bundles/seg-12.tar \
  https://<your Govern host>/api/v1/audit-logs/cold-segments/12/bundle

keystone-audit-verify cold --dir ./bundles --keys keystone-audit-keys.json --org <organization id>

Each download is audited (audit.cold_segment.downloaded) before it is sent. Segments without the organisation's entries are reported as warnings; consecutive bundles must still link. The sequence as a whole is proven by the operator's platform verification.

Neither the bucket listing, nor a manifest, nor the spine names a tenant: an organisation finds its own object from its own id, and cannot tell which rows belong to the same other tenant or when they were written.

Last reviewed 17 October 2026View as Markdown

Verify offline · Docs · Neural Inverse