ops-warden/wiki/AuditTrail.md
tegwick 94f32bd160
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Review layer model v0.6; publish the PEP stance map §6.4 requires
All three v0.4 findings were acted on — §9.1 split into pending/declared-gap and
§5's scope rule adopted as recommended and credited, and §9.6 ruled via the
load-bearing/attributive distinction with ops-warden's `# audit must not block
signing` named as the estate's live example.

Checked the favourable ruling rather than accepting it. §9.6's test is "no
control branches on its presence": the only consumer of audit.jsonl is `warden
activity`, which displays. Nothing gates on a signing record, so the lane is
genuinely attributive. AuditTrail.md now records the ruling instead of the open
question, and states that the trade must be revisited if a control ever gates on
the trail.

CONFORMANCE ACTION. §6.4 obligation 3 requires a stance map "published rather
than held in code", and requires every PEP-shaped consumer to publish one so the
maps can be inventoried — naming ADR-0009 as the reference shape. ops-warden was
not doing it: the map lived in PolicyConfig.failure_modes, a dataclass default.
Not a code comment, but not published either.

pep-stance.yaml publishes it, and the test asserts the published map EQUALS the
shipped default. A published map that may drift from the code is worse than no
map, because it invites reliance it cannot support.

Two findings sent to gate-house, in history/2026-08-29-layer-model-v06-review.md:
§6.4 obligation 1 (no side effect without a decision record) contradicts
obligation 3 and §9.3, with ops-warden's blessed fail-open stance as the
instance; and §6.4 mandates a stance-map inventory in §13 that §13 does not
implement — where ops-warden is currently the only PEP to have published one.

402 tests pass, ruff clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YWBMovyFoy9RRrfL7zKvPJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 10:20:49 +02:00

3.4 KiB

Audit Trail — Unified ops-warden Activity

Date: 2026-07-01
Workplan: WARDEN-WP-0022

ops-warden records metadata only for every action it performs. No token, key, cert body, or other secret value ever lands in the audit log.


What is recorded

Kind Source actions Typical fields
sign warden sign, warden issue, cert_command actor, backend, TTL, policy_decision_id
access warden access --fetch / --exec need id, owner repo, subject, decision id, outcome
worker warden worker tick, approve, full-auto execute triage counts, draft id, outcome
hub State Hub progress notes (--hub) summary, author, event type

Storage

  • Primary: {state_dir}/audit.jsonl — append-only JSONL (default ~/.local/state/warden/audit.jsonl)
  • Legacy (merged for back-compat): signatures.log, access-audit.log

Rotation: when audit.jsonl exceeds 5 MiB it is renamed to audit.jsonl.1 and a fresh file starts.

Secret-material guard

record_event() rejects fields that look like secret values (known token prefixes, high-entropy runs). Signing and proxy paths swallow audit failures so gatekeeping never blocks the primary action — but tests prove values cannot be written.

Absence of a record is not evidence of absence. Because emission never blocks the primary action (src/warden/ca.py), a failed append loses the event while the action still happens. This trail proves that the records it holds were not altered or truncated; it does not prove that every action produced one. Do not reason from a missing entry. This is the estate-wide bound in security-layer-model_v0.4 §9.6 — completeness is the source's obligation, and Ruled 2026-08-29 (security-layer-model_v0.6 §9.6): this trail is attributive, not load-bearing — no control branches on the presence of a signing record — so the non-atomic trade is legitimate, and the obligations are to declare it (this note) and never to claim completeness. Atomicity is required only where a control's soundness depends on an event being present or absent. Registered in the standard's §13 open-gap table as self-declared. If a future control ever gates on this trail, the trade must be revisited before it ships.


Query

# Human table — last 7 days
warden activity

# Filter and JSON for agents
warden activity --days 3 --kind sign --json
warden activity --days 7 --hub --json
Flag Purpose
--days N Look back N days (default 7)
--kind sign|access|worker|hub Filter by event kind
--json Stable JSON array for automation
--hub Include recent State Hub progress notes mentioning ops-warden

Linger and login independence

The coordination worker can run under a systemd --user timer with linger enabled (WARDEN-WP-0021). Audit events from worker ticks appear with kind: worker.

Full logged-out operational value still depends on State Hub and tunnels being reachable without an interactive login (State Hub on railiance01, cust-wp-0011). The audit trail is local-first; --hub adds narrative context when the hub is up.


See also

  • wiki/OperatorAccessAssist.md — metadata-only principle for access proxy
  • wiki/PolicyGatedSigning.mdpolicy_decision_id on sign events
  • wiki/playbooks/scheduled-worker.md — worker timer and review loop