Repository navigation
Conversation
…t to logs An audit event names a person, their email and their IP address. As a log it was readable by every member and writable by anything holding an ingest key. The gateway now writes these to audit_trail_events, behind audit_log:read. Gateway (apps/ingest): - New audit_trail module: Vercel audit drain events and GCP Admin Activity and Policy Denied entries as rows, with the same key derivation as the TypeScript writer. GCP System Event entries are Google's own actions and stay logs. - The Vercel audit drain has its own handler. It refuses the public ingest key, which ships in browser bundles, and acks and drops while the integration's source is paused. - A GCP audit entry is stored ahead of the plan check on logs and is not metered. - A gateway that only forwards has no such table: there both feeds stay logs. Web: - The audit log page gets its platform filter, column and detail row back, with Vercel and Google Cloud named. Target shows on wide screens only, so Outcome stays on screen beside the rail. - /infra/vercel no longer reads audit events from logs. Its rail points at the Security audit log when the drain is on. The query, endpoint and row schema behind the old panel are removed. - The Vercel and GCP setup copy and the public docs say where these events land.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
This comment has been minimized.
This comment has been minimized.
…ded and off by default Review of the Vercel and GCP layer: - The Vercel audit drain accepted any private key or source token. It now takes only the drain Maple creates: the private key naming one of the org's integration sources. - A delivery is decoded inside the shared decode memory budget and capped at 4 MiB; a small gzip could otherwise parse into gigabytes. - Audit rows are unmetered, so each org has a delivery rate, every column a cap, and a timestamp outside the table's retention is replaced by the time of receipt. - Kubernetes API writes stay logs. Categories are matched on whole words, a federated workload is a named service, and Vercel rows carry a target. - INGEST_AUDIT_TRAIL_ENABLED (default off) turns the trail on, so the gateway can deploy before the table exists and is switched off rather than rolled back past the new WAL frame tag. - The handler records request metrics like the other ingest routes. - Tests read the stored row instead of the returned count.
This comment has been minimized.
This comment has been minimized.
… to retry verify_source_claims left a claim unverified when the store could not be asked, and the audit handler read that as an unknown sender (401). The drain then looked misconfigured during a Postgres blip. The lookup now reports the failure and the handler answers 503, as the key lookup does.
Maple review🟢 Confidence 10/10 · safe to merge. Both audit parsers and every refusal path of the new drain handler are pinned by tests; only the prd flag ordering has to be honoured at deploy. Vercel audit-drain and GCP Admin Activity/Policy Denied entries now land in
Before merge
Fixed since the last review
Production impactOpen errors in the changed files (2)
After this merges, Maple checks whether they stop.
|
🍁 Maple PR previewWarning Preview cleanup could not be confirmed. The Alchemy teardown outcome was Final commit |
Third layer of the unified audit log, on top of #2520: Vercel and Google Cloud audit events stop being logs.
Why
An audit event names a person, their email and their IP address. Stored as a log it was readable by every org member, reachable from raw SQL, dashboards and the agent, and writable by anything holding an ingest key: the Vercel panel selected rows purely by
service.name = vercel-audit-log. The gateway now writes these toaudit_trail_events, which onlyaudit_log:readcan read and only provider adapters can write.What changed
Gateway (
apps/ingest)audit_trailmodule turns Vercel audit drain events and GCP Admin Activity and Policy Denied entries into rows. The key derivation matches the TypeScript writer and both sides assert the same two vectors.INGEST_AUDIT_TRAIL_ENABLEDturns it on. Off, or on a gateway that only forwards (self-hosted), both feeds stay logs exactly as before. Non-production stages set it; production sets it in its environment (see "Before merging").x-maple-source-idnaming one of the org's integration sources. The public key, a source token, a private key naming no source, and a key naming another org's source are refused with 401. Existing drains already send both, so they keep delivering.k8s.io, mostly a cluster's own controllers, thousands an hour). Data Access entries were already filtered out by the sink.permission, password protection isconfiguration,environmentis notenv. GCP reads the call itself (setIamPermissions,SetOrgPolicy, sink changes). A federated workload with only aprincipalSubjectis a named service. Vercel rows fill the target from the action and its payload.Web
/infra/vercelno longer reads audit events from logs. When the drain is on, its rail points at the Security audit log. The query, endpoint and row schema behind the old panel are removed.Before merging
INGEST_AUDIT_TRAIL_ENABLED=truein the gateway's environment, set onceaudit_trail_eventsis in Tinybird (the rollout step on feat(security): audit_trail_events table, list endpoint and Maple's own events #2510) and this build is the one running. The gateway can deploy at any time before that: off, it behaves as today./infra/vercelaudit panel is gone as soon as web deploys, and Vercel audit events are still logs until the switch is on. They stay readable in the logs explorer in between.vercel.audit.*,gcp.audit.*or thevercel-audit-logservice stops matching new events. I could not check other orgs' alert rules and dashboards from here. That needs a look at production.Not in this PR: verifying Vercel's
x-vercel-signaturewith a per-drain secret. The sender check above stops every credential except the org's private key; a holder of that key who also knows the source id can still post an event. Closing that needs a stored drain secret.Screenshots
/infra/vercelrail, from the lab. The old group listed the three newest audit events to every member.Verified
cargo test --lockedpasses: 376 library tests and 213 binary tests. The gateway tests read the row that reaches a fake Tinybird: a Vercel delivery and a GCP entry each land inaudit_trail_eventswith their org, event id and actor, and the GCP entry does not reach the org's logs. Also covered: the four refused senders, a paused source acked and dropped, a gzip delivery that inflates past the limit (413), the per-org rate, column caps, the timestamp window, the category tables, andk8s.iostaying a log. Clippy is clean on the new module.oxlint -c .oxlintrc.effect.jsonis clean on the 33 changed TypeScript files.ui:index,ui:patterns:checkand the UI kit baseline are unchanged.Known flake, not from this change:
grpc_export_takes_gzip_within_the_http_body_limitsfailed in 2 of 20 local runs of the gateway's binary tests. It does not touch this code.Not verified: against a real Vercel audit drain or a real GCP sink.
preview:webhas no ingest gateway, so this layer needs a fullpreviewto exercise end to end. The category for a Vercel action is read off its name, because Vercel publishes no closed list; unrecognised actions are filed as resource changes.