Audit Trail
"A log is only as useful as the chain of custody that makes it admissible."
Overview
Aura's audit trail is the intent log: an append-only, cryptographically chained record of every significant action taken against a repository. Every commit, every rewind, every zone claim, every agent capability exercised produces an entry. Entries are signed by their author, linked to their parents by hash, and exportable as JSONL for SIEM ingestion. Auditors verify the chain by recomputing hashes; no trust in Aura, the Mothership, or the host OS is required to validate continuity.
This design is motivated by a specific operational need: when something goes wrong — a secret leaks, a production-breaking change ships, a malicious commit appears — the first question is "what happened and when?" The second is "can we trust the record?" Aura is built so the answer to the second question is yes.
Threat Scope
The audit trail defends against three failure modes:
- Forgery. An attacker attempts to inject a false entry — e.g., an intent attributing a malicious change to an innocent author. Defended by Ed25519 signatures; forgery requires the author's private key.
- Tampering. An attacker attempts to modify or delete an existing entry to cover their tracks. Defended by the Merkle chain; any modification breaks the hash continuity for every subsequent entry, and because peers replicate the log, divergent tips are detected on sync.
- Omission. An attacker attempts to prevent an entry from being recorded at all. Partially defended: peers keep local tips, and a peer whose log is shorter than its peers' detects the gap on sync. An attacker who controls both the Mothership and the committing peer can, however, silence a single entry. This is a genuine limitation; see below.
The log does not defend against an attacker with the author's private key. Nothing in authenticated-append-log designs can. What it does provide is an unambiguous attribution record: every action is tied to a specific key, and if that key is later revoked or rotated, the window of authority is exactly the log range in which the key was valid.
Mechanism
Entry structure
Each intent log entry is a canonical JSON object with the following fields:
{
"version": 1,
"id": "in_01J2ABCDEFGHJKMNPQ",
"ts": "2026-04-21T14:32:17.481Z",
"author": {
"kind": "human",
"id": "alice@example.ch",
"peer_id": "peer-5f3a",
"pubkey": "ed25519:4e5f...a1c2"
},
"capability": "commit",
"intent": "Refactor retry_logic to use exponential backoff for rate limit compliance",
"ast_delta": {
"added": 2,
"modified": 3,
"removed": 1,
"nodes": [
{ "path": "src/net/retry.py:retry_logic", "before": "blake3:7f2c...", "after": "blake3:9a1b..." }
]
},
"ast_delta_hash": "blake3:c4e9...",
"parents": ["blake3:a0d1..."],
"hash": "blake3:f3b2...",
"signature": "ed25519:5a12...e9cc"
}
idis a sortable ULID, human-useful but not security-relevant.tsis the author's clock; Aura does not require time synchronization, but SIEM ingestion usually does.parentsis a list — normally one, but two or more for merge commits.hashis the BLAKE3 hash of the canonical encoding of all other fields exceptsignature(signatures are added after hashing).signatureis the Ed25519 signature overhash.
Each field's role is precise: ast_delta_hash commits the log entry to a specific semantic change, parents chains the entry to history, and signature binds the entry to the author's identity key.
The hash chain
Entries form a Merkle chain. For entry N, parents[0] is the hash of entry N-1. To verify the chain from genesis to tip:
- Parse each entry in order.
- Recompute
hashfrom the canonical encoding of non-signature fields. - Verify the recomputed hash matches the stored
hash. - Verify
parents[i]references the correct predecessor's hash. - Verify
signatureagainstpubkeyandhash.
A single mismatch invalidates every subsequent entry. Auditors running aura audit verify receive a pass/fail along with the first broken index (if any).
Merge commits introduce multiple parents; the chain becomes a DAG rather than a linear list. Verification accommodates this by processing every ancestor before a descendant.
Append-only semantics
The log file is append-only at the filesystem level (fadvise FADV_APPEND on Linux where available; append-open-mode elsewhere). Aura writes entries with a fsync at each append, so a power loss cannot corrupt prior entries.
There is no aura rewrite-history subcommand. There is no analog to git rebase -i. A mistaken intent cannot be edited; it can only be superseded by a subsequent entry that corrects the record. This is a deliberate, and sometimes inconvenient, design choice: audit integrity requires that past statements remain visible even when the authors regret them.
Supersede entries
When a committer realizes an earlier intent was wrong or misleading, they may file a supersede entry:
aura intent supersede <intent-id> "Previous intent misstated the cause. Actual cause: upstream rate-limit change."
This writes a new entry referencing the old one. Both remain in the log. Diff and trace tooling display the superseded entry with its correction; audit tooling preserves both. Supersede entries cannot delete; they can only annotate.
Chain validation
aura audit verify
aura audit verify --from <intent-id>
aura audit verify --signatures-only
aura audit verify --since 30d
The verifier reports one of:
OK — N entries, M signatures valid, chain continuousBROKEN — first inconsistency at entry <id>: <reason>
Inconsistencies fall into categories: hash mismatch, parent not found, signature invalid, unknown signer (public key not in the known-keys set), clock regression beyond tolerance. Each category is a distinct enum in the output, so SIEMs can alert on specific failure modes.
Export for SIEM
aura audit export --format jsonl --since 2026-01-01 > audit-2026-q1.jsonl
aura audit export --format syslog --host siem.internal:514
aura audit export --format otlp --endpoint https://collector.internal
JSONL emits one entry per line, preserving the full structure above. Syslog emits RFC 5424 messages with the intent summary and key hashes. OTLP emits OpenTelemetry-logs records for native SIEM ingestion. All three formats carry enough information for an external verifier to re-run the chain validation independently — the log is self-contained.
Cross-branch intent
Intents associated with live-sync function updates across branches are recorded with a branch field and a cross_branch marker where applicable. This allows auditors to reconstruct the flow of a change as it propagated across the team's working branches — not just the eventual merge.
Retention
The intent log is retained indefinitely by default. Three retention knobs exist:
retention.keep_forever = true— the default. No pruning.retention.archive_after_days = N— move old entries to compressed archive files after N days. Archives are still signed and verifiable; they are just not loaded into memory by default.retention.redact_pii_after_days = N— only theintentfree-text field is scanned for PII and tokenized after N days. The cryptographic chain is unaffected.
Pruning entries entirely is not supported. If your regulatory regime requires deletion, your options are to archive + encrypt with a separate key that you destroy on schedule (tombstoning the payload while keeping the chain intact), or to run a separate disposable Aura instance for short-retention data. Naridon will not ship a chain-modifying delete command because doing so would defeat the point of the log.
Configuration
[audit]
# Path to the log; append-only, back it up
log_path = "/var/lib/aura/intent.log"
# How often to fsync (in entries). 1 = every entry. Lower values trade durability for throughput.
fsync_every = 1
[audit.export]
# Enable continuous SIEM export
enabled = true
format = "otlp"
endpoint = "https://collector.internal:4318"
# Failure policy if the collector is unreachable
# "buffer" = retain locally and retry, "fail_commit" = refuse new commits if unable to ship
on_failure = "buffer"
[audit.retention]
keep_forever = true
archive_after_days = 365
Sample verification run:
$ aura audit verify --since 90d
reading 4,812 entries from 2026-01-21 to 2026-04-21
hashes: 4,812 / 4,812 OK
parents: 4,812 / 4,812 OK
signatures: 4,812 / 4,812 OK (17 distinct signers)
chain: continuous
OK
Limitations
- An attacker who controls both the committer's key and the local log file can forge a consistent chain prefix, up to the point at which their fork last matched any peer's copy. Peer replication limits this window: as soon as another peer is aware of a tip past the fork point, the fork is visible. High-security deployments should ensure frequent Mothership sync and alert on any detected fork.
- Timestamp integrity is author-controlled. Aura does not timestamp entries with an external trusted time source. If entry-ordering evidence requires RFC 3161 timestamping or a similar scheme, integrate it at the export layer.
- The intent free-text field is not structured. An auditor cannot query "find all intents about the payment module" without text search. Projects that require structured intent categorization should define a convention (tags in the intent text) and enforce it via commit hook.
- Volumes scale linearly with activity. A busy team may produce tens of thousands of entries per month. Plan storage and SIEM ingest accordingly; the archive mode exists for exactly this reason.
- Legal hold requires cooperation. If an auditor demands preservation of a specific period's log, take a signed snapshot of the log file (
aura audit snapshot <path>) and store it offline. The snapshot is independently verifiable.
See Also
- Threat model — adversaries the log must resist
- Cryptographic design — signature and hash primitives
- Agent permissions — how agent actions appear in the log
- Compliance and audit — mapping the log to regulatory controls
- Secret detection — how overrides are recorded
- Aura trace — reading the log for investigation
- Incident response — using the log after a compromise