Define canonical, tamper-evident audit-event schema and local query contract #487
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Define one versioned audit-event contract used by every bot-bottle security and provenance producer, with a canonical append-only representation, tamper-evidence, useful local search, and a stable mapping to the centralized provenance stream.
Today the pieces are fragmented:
AuditEntry/supervise_audit_entriesis specific to supervisor decisions and cannot represent lifecycle, egress, commit, forge, authentication, or host-controller events.Without a shared contract, each producer will invent incompatible fields and integrity semantics, making local search, cross-host correlation, replay, and incident reconstruction unreliable.
Security requirement
The audit trail is security evidence, not ordinary diagnostic logging. An agent must not be able to choose or forge host-owned attribution fields, splice/reorder events undetectably, inject secrets into the record, or exploit differences between the local journal, local index, and exported representation.
This issue defines the contract; implementation may be split into follow-up PRs.
Proposed architecture
The local audit must remain usefully searchable without the paid platform. The platform value is cross-host aggregation, off-box retention, correlation, alerting, RBAC, and compliance-oriented queries/exports.
Contract to specify
Versioned envelope
At minimum:
schema_versionevent_idevent_type/ event-name registryprevious_hash,event_hash, chain/segment identity)The specification must distinguish fields supplied by the host/control plane from untrusted claims copied from a bottle, gateway, forge, or remote response.
Canonicalization and integrity
Define:
Storage and local query
Export/interoperability
Initial event registry
Cover at least:
Each type must document required attributes, which fields are trusted vs. claimed, redaction rules, and correlation behavior.
Acceptance criteria
Dependencies / ordering
Non-goals
@didericis-codex debating whether all outbound requests should also be logged... there are probably better tools for that specifically, so leaning no, but would be kind of nice to have an all-in-one monitoring service built into bot bottle that could look at that. thoughts?
I lean no for the canonical audit journal, yes as a separate telemetry stream that the same service can ingest and search.
“All outbound requests” has very different volume, privacy, retention, and integrity requirements from security audit evidence. Putting every allowed request in the permanent hash-chained journal would make the important events harder to find, increase disk/export cost, and create a new sensitive-data liability (URLs, query strings, headers, and bodies routinely contain secrets). It also encourages #487 to become an observability platform rather than a crisp audit contract.
I would split it into three levels:
The all-in-one monitoring experience can still be a strong bot-bottle/platform feature: one UI correlates audit events, egress telemetry, lifecycle, approvals, and signed commits. They do not need to share one storage/retention policy to appear in one timeline. Exporting access telemetry through OpenTelemetry also lets users send it to Loki/Elastic/Splunk/etc. instead of requiring us to outbuild dedicated log systems.
For #487, I would include an event class/sensitivity/retention field and reserve
egress.request/egress.aggregateevent shapes, but make the acceptance criterion only that security-relevant egress decisions enter the canonical audit chain. A separate issue should define full access logging, aggregation, redaction, sampling, and retention. That gives us the integrated product path without silently turning the audit log into packet surveillance.@didericis-codex for sure, should be different buckets. Let me explain my thought process for context.
Before going much further I want to make sure the bottlenecks we've created can give us the monitoring capabilities we need, and surface any potential issues with how we plan to record that monitoring data and make it comprehensive before we bolt on more features. Part of that logic is to make sure that we don't create any features that work against that comprehensive monitoring, which we'd detect earlier if it were implemented.
For traffic monitoring (and process monitoring in the future), I'm not sure if we really need to do anything/I think the bottleneck is already there. I think we could simply put another existing tool in the gateway egress for traffic monitoring. Process monitoring is a different story, but I think we could similarly use built in monitoring tools for firecracker, docker, and macos containers.
Given that I think we can probably skip the aggregate telemetry and request access logs for now.
Thoughts?
Yes — I think that is the right scope. We do not need to build aggregate telemetry or request access logs now. We need to make sure the architecture does not foreclose them and that the bottlenecks really cover what we think they cover.
For traffic, the gateway is already the right observation point provided the network invariant is true: all permitted application egress traverses it, and anything that does not traverse it is blocked. I would document/test that invariant and enumerate intentional exceptions (DNS plumbing, host-controller traffic, backend management links, etc.). Then a future collector can be inserted at the gateway without changing bottle-facing APIs.
The one design hazard worth surfacing now is placement relative to credential injection. The gateway inserts real provider/forge credentials that the bottle never sees. A generic traffic monitor placed after injection—or a packet-capture tool on the wrong interface—could turn the monitoring store into a credential leak. Future monitoring must either observe before secret injection, collect metadata only, or have a strict redaction boundary owned by trusted code. We should preserve an explicit hook/location for that rather than assuming any off-the-shelf gateway monitor is safe.
The other readiness invariants I would capture now are:
Process monitoring can remain a later backend-specific adapter problem. Firecracker, Docker, and Apple containers expose different primitives; we should normalize their output only when there is a concrete use case, rather than inventing an abstraction now.
So my recommendation is: skip traffic/process telemetry implementation for now, keep #487 focused on the canonical security audit contract, and add only observability-readiness invariants/tests where upcoming architecture work could accidentally create a bypass or expose injected secrets. An existing monitoring tool can be evaluated later against those invariants.
Yep, bottled agent ids should be assigned by the orchestrator registry, and audit events should occur before we use them.
This is the part I was debating about just implementing now/maybe normalizing to our own shape for a future all in one service... It should be pretty simple. Would probably just want to shove some existing tool which spits out the requests (and responses?) from the mitmproxy to the control-plane.
Don't want to deal with this now, but should probably just be a write only spigot/no ack by default, maybe with some kind of ack behavior you could turn on to ensure no egress logs are dropped
Timestamps and bottled agent ids should probably be sufficient.
Yeah, only HTTP(S) for now (and no deep request monitoring when inspect is off)
That all sounds directionally right. I would keep the implementation deliberately small if you do it now: a mitmproxy addon emits a normalized, metadata-only flow record to a control-plane ingestion endpoint. Do not forward the raw mitmproxy flow object and do not treat this as the canonical audit writer.
A few boundaries I would keep explicit:
inspection_mode/visibility explicitly so absence of method/status is not mistaken for missing data.On lifecycle ordering, yes: allocate/register the bottled-agent + activation IDs first, append the lifecycle/audit event that establishes them, then permit launch/traffic that references them.
If implemented now, I would still put the telemetry spigot in a small separate issue/PR from #487. #487 can define the shared envelope dimensions and trust labels; the spigot proves the choke point is usable without making request telemetry part of the permanent security-audit promise.
@didericis-codex file details about the telemetry spigot in a new issue
@didericis-claude create a new PRD for this. We'll do this immediately after the host controller and wire these audit events into the host controller.
didericis referenced this issue2026-07-26 03:12:56 -04:00
Done — opened #495 with a draft PRD: Canonical tamper-evident audit-event schema and local query contract (
docs/prds/prd-new-audit-event-schema.md).It defines a single versioned
AuditEventenvelope with a structural trusted/untrusted split, canonical-JSON + per-writer hash chain for tamper-evidence, an append-only JSONL journal as source of truth with a rebuildable SQLite index for local query, an initial event registry (lifecycle.*/decision.*/egress.*/auth.*/forge.*), and an enforced redaction rule.Per your note, it's sequenced to land right after the host controller (#468) — the host controller is the first producer, emitting
lifecycle.*through the new envelope, and the existing supervise/egress/git-gate/auth producers migrate behind it. Open questions (single-writer vs per-producer chains, clock/ordering across restarts, reject-vs-redact) are called out at the end for your feedback.