Reliable multi-tenant auto setup audit capability
Find a file
tegwick 0ad526c2d8
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Bind sender identities, add operator read surface, real serving layer
AUDIT-WP-0004 T03, T05, T06.

T03 - the receiver accepted whatever tenant and source a caller sent as long
as it held the one shared token, despite WP-0003 recording tenant isolation as
delivered. audit_core.senders binds each credential to the sources and tenants
it may assert, driven by AUDIT_CORE_SENDERS rather than literals. Identities
hold a list of tokens so rotation publishes the replacement alongside the
incumbent and needs no delivery gap. Read is a separate privilege from write,
so a sender credential cannot read the audit trail back.

T05 - lookup by event id, lookup by correlation id, and a dead-letter view.
Rejections are recorded rather than silently dropped. An event rejected for
carrying secret-shaped material has its payload withheld: storing it would
write that material into the audit store, which is what the rejection exists
to prevent. Reason and payload hash are kept so it stays traceable.

Replay is deliberately not built here. Idempotent replay is a property of the
durable store and building it against SQLite would produce a second
implementation to throw away; it lands with the Postgres backend in
AUDIT-WP-0005-T01.

T06 - serving moves to waitress with configurable threads and channel timeout,
installed in the image via the serve extra. Without it the entrypoint falls
back to a threaded wsgiref server with a socket timeout and graceful shutdown
on SIGTERM, and logs a warning so a deployment cannot quietly land on the
fallback. Metric counters deferred to WP-0005-T03 to be designed against the
real scrape path.

Tests 36 -> 46, covering cross-tenant and cross-source refusal, token
rotation, read/write privilege separation, correlation lookup, and payload
withholding on secret rejection.

Remaining in WP-0004: T04 redaction policy, which needs a decision on whether
a secret-shaped field is a rejection or a redaction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 14:50:02 +02:00
.claude/rules docs: workplan-first agent guidance prose (CUST-WP-0055 T04 batch 5) 2026-07-08 19:50:55 +02:00
.forgejo/workflows Add Forgejo CI smoke workflow (enablement template) 2026-07-08 12:28:40 +02:00
audit_core Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00
docs Moved audit forward somewhat 2026-07-04 00:39:03 +02:00
registry Add capability registry with seed entry from reuse-surface 2026-06-16 01:46:53 +02:00
spec Added PRD for what we want to do 2026-06-01 23:38:26 +02:00
tests Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00
workplans Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00
.custodian-brief.md chore(consistency): sync task status from DB [auto] 2026-08-10 12:44:56 +02:00
.gitignore Initial commit 2026-06-01 21:16:10 +00:00
.repo-classification.yaml Human-review .repo-classification.yaml (CUST-WP-0050 follow-up) 2026-06-22 17:56:17 +02:00
AGENTS.md Regenerate agent instructions from state-hub templates (CUST-WP-0055 T01) 2026-07-08 14:50:17 +02:00
CLAUDE.md Normalize agent instructions and workplan frontmatter (STATE-WP-0067) 2026-06-22 23:16:24 +02:00
Containerfile Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00
INTENT.md Seeded repo with intent 2026-06-01 23:20:04 +02:00
LICENSE Adopt Target Revenue Source License V1C1 (org-wide preliminary rollout) 2026-07-29 23:53:10 +02:00
Makefile Add mock file audit backend 2026-06-01 23:44:03 +02:00
pyproject.toml Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00
README.md Moved audit forward somewhat 2026-07-04 00:39:03 +02:00
SCOPE.md Seeded intent, scope and workplan 2026-06-22 17:52:32 +02:00
WORK-RECORDS.md Bind sender identities, add operator read surface, real serving layer 2026-08-10 14:50:02 +02:00

Reliable multi-tenant auto setup audit capability

Backend contract

The pluggable backend interface, event schema (audit-core.event.v1alpha1), retention policy, and migration path from the mock file backend are documented in docs/audit-backend-contract.md.

Development Mock Backend

The first implementation is intentionally tiny: a replaceable audit interface with a mock file backend.

By default it writes JSONL audit events to:

/tmp/audit-core/audit-YYYYMMDDTHH.jsonl

Files older than 7 days are removed when the backend writes or when cleanup is run explicitly. This backend is for local integration and bootstrap wiring. It is not durable audit custody.

Example:

python3 -m audit_core emit \
  --source openbao \
  --action openbao.authenticated_readiness_proof \
  --resource openbao/openbao-0 \
  --outcome success \
  --detail file_audit_visible=true \
  --detail backend=mock-file

Cleanup:

python3 -m audit_core cleanup

Make targets:

make test
make mock-audit-smoke
make mock-audit-cleanup

Environment:

  • AUDIT_CORE_MOCK_DIR: override the output directory.
  • AUDIT_CORE_MOCK_RETENTION_DAYS: override the default 7-day cleanup window.