Skip to content

Audit Log Format

ShadowAudit stores runtime decisions in a local SQLite database. The current table is audit_events.

Schema

CREATE TABLE audit_events (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    agent_id TEXT NOT NULL,
    task_context TEXT,
    risk_category TEXT,
    decision TEXT NOT NULL,
    risk_score REAL,
    threshold REAL,
    payload_hash TEXT,
    reason TEXT,
    latency_ms INTEGER,
    timestamp REAL NOT NULL,
    prev_hash TEXT NOT NULL DEFAULT '',
    entry_hash TEXT NOT NULL DEFAULT '',
    signature TEXT
);

Decision values

The audit table stores direct gate outcomes as:

Value Meaning
pass The gate allowed execution.
fail The gate blocked execution.

Policy and approval details may also appear in result metadata or the approval database.

Hash chaining

Each row stores prev_hash and entry_hash. The entry hash is computed from the canonical event fields and the previous entry hash.

entry_hash = SHA-256(canonical_event_fields + prev_hash)

If an old row is modified, deleted, or reordered, verification fails.

Signatures

When AuditLogger(sign_entries=True) is used, audit entries are signed with Ed25519 and the signature is stored in the signature column.

Querying directly

import sqlite3

conn = sqlite3.connect("audit.db")
rows = conn.execute("""
    SELECT id, timestamp, agent_id, task_context, risk_category, decision, reason
    FROM audit_events
    ORDER BY timestamp DESC
    LIMIT 50
""").fetchall()

CLI access

shadowaudit logs --audit-log audit.db --json
shadowaudit verify --audit-log audit.db