Protect a database

The wire proxy

This is gmonk's main path. The proxy sits in the database connection, so it does both jobs at once: it prevents statements it couldn't undo, and it captures the before-image of the ones it allows.

Terminology. In gmonk, "the proxy" always means this — the database wire proxy. The MCP gateway that captures an agent's tool calls is a different interception point and is not a proxy. If you connect with a postgres:// URL, you're using the proxy.

Run it

bash
# your database URL lives in an env var — never passed on the CLI or stored
export APP_DB_URL=postgres://user:pw@db-host:5432/appdb

gmonk protect --backend-ref APP_DB_URL --listen 6432

# then point the agent at gmonk instead of the database:
#   postgres://agent@localhost:6432/appdb

MySQL works the same way. gmonk protect picks the dialect from the URL scheme, so a mysql:// backend launches the MySQL wire proxy and the agent points at mysql://agent@localhost:6432/appdb.

What happens to a statement

  1. Authenticate — the proxy records who the agent is.
  2. Connect as gmonk — it holds its own backend connection using gmonk's role, rather than relaying the agent's identity. This is what makes it compose with enforcement.
  3. Gate — every statement is scored by the reversibility oracle. DROP, TRUNCATE and a DELETE with no WHERE are refused at the wire and never reach the database.
  4. Capture, then forward — the before-image is snapshotted on the agent's own connection, in the same transaction as the write.

Reads are relayed verbatim, both directions. gmonk does not parse or re-encode result sets, so there is no risk of mangling them.

What it captures

Single-table UPDATE, DELETE and INSERT — plain or parameterized, in autocommit or inside a client-managed transaction. INSERT is captured with a RETURNING to_jsonb(t) rewrite. A Parse batch on the extended protocol is buffered to its Sync and gated as one unit.

Undo is operation-based where it can be: an additive change like balance - 30 reverses as + 30, which preserves a concurrent write instead of clobbering it with a stale absolute value.

Hardening

Flag / variableWhat it does
--guarantee Prove-then-commit: refuse any write gmonk can't prove it can undo. Works inside a client transaction via SAVEPOINT-bracketed rollback.
GMONK_PROXY_PASSWORD
--tls-key / --tls-cert
Require a password and encrypt the client → gmonk hop. Needed to run beyond loopback.
GMONK_PG_BACKEND_TLS
GMONK_MYSQL_BACKEND_TLS
The gmonk → database hop. Host-aware by default: a remote target is require (gmonk refuses to send its credentials in cleartext), loopback is prefer.
gmonk enforce Revoke the agent's direct write grants so the proxy is the only way in. See Enforcement.

Honest limits

  • Binary-format bind parameters fall back to WAL or trigger capture — text params are inlined.
  • Extended-protocol Flush pipelining is not yet handled.
  • SCRAM (client- and backend-facing) is not implemented; MD5 client auth is.
  • MySQL: guarantee mode is an advise-fallback — the prove-then-commit rollback plumbing is Postgres-only for now. Multi-row and non-auto-increment INSERT are flag-only, and the blast-radius minRows guard is Postgres-only.
  • Only single-table statements. The proxy finds the affected rows by parsing, so a multi-statement batch, a CTE, a cascade, a join or a range update is not captured here — parsing can't prove which rows those touched. They're flag-only unless the table also carries a capture trigger, which observes the real row changes. Same for binary bind params and statements with their own RETURNING.