Protect a database
Enforcement & anti-bypass
Capturing and reversing only helps if the write comes through gmonk. This page is the answer to the fair objection: "what about a write that skips your gateway — a stray psql, an ORM, another service?"
On a protected table, a write cannot hide
gmonk protect-db installs a
BEFORE INSERT/UPDATE/DELETE trigger on each protected table. It
fires in the same transaction as every write, whoever made
it, and records the row's before/after. A write that came through gmonk
carries an action_id; one that skipped the gate has
action_id IS NULL.
Either way gmonk captured the before-state — so a bypassing write is still fully reversible. It didn't escape capture; it only skipped the gate.
Bypassing writes become flagged, reversible actions
gmonk coverage # one-shot: detect + reconcile + report
gmonk coverage --watch 30 # continuous: reconcile every 30s and alert coverage finds the unattributed capture-log rows, groups them by
transaction, and promotes each into a first-class flagged action under the
run out-of-band. Each one then:
- shows up in the timeline, next to gated activity;
- is reversible like any other action —
gmonk reverse-run out-of-band --only <seq>; - fires an alert (the
out_of_bandevent, on by default) so you know the gate was skipped and can investigate why.
gmonk's own undo writes suppress the capture trigger, so reversing a change is never mistaken for a bypass — no false positives, no undo-the-undo loop.
coverage only claims unattributed
rows older than GMONK_OOB_GRACE_SECONDS (default 30), so an
in-flight gmonk operation adopts its own rows first. Promotion consumes the
log rows, so each bypassing transaction is reconciled exactly once, and all
rows from one transaction become one action reversible as a unit.
Close the door entirely
Detection is good; making a bypass impossible is better. Enforcement revokes the agent role's direct write access, so the only path to a write is through gmonk — after which a direct write is rejected by the database itself.
gmonk assure --agent-role <role> # read-only: is the perimeter closed?
gmonk enforce --agent-role <role> # revoke the agent's direct writes -
assureclassifies every table for the agent's role and reports the invariant. Read-only — it's the proof artifact. -
enforcerevokesINSERT/UPDATE/DELETE/TRUNCATEon the in-scope tables from that role. It never touches gmonk's own role, so writes through gmonk keep working. It's owner/superuser-level: setGMONK_ADMIN_DATABASE_URL(or--target-ref), and it supports--dry-run.
This is also why the wire proxy terminates rather than relaying the agent's identity: it connects as gmonk's role, so it still works once the agent's own grants are gone.
What this does and doesn't cover
- Covers: any write to a protected table, through any client. On a protected table you cannot bypass capture — only the gate — and gmonk sees, records, reverses and reports it.
- Doesn't cover: tables you haven't protected; effects outside the database (see external effects); and multi-tenant attribution of bypassing writes.