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

bash
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_band event, 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.

Grace window. 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.

bash
gmonk assure  --agent-role <role>     # read-only: is the perimeter closed?
gmonk enforce --agent-role <role>     # revoke the agent's direct writes
  • assure classifies every table for the agent's role and reports the invariant. Read-only — it's the proof artifact.
  • enforce revokes INSERT/UPDATE/DELETE/TRUNCATE on 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: set GMONK_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.