Skip to main content

Module pg_client

Module pg_client 

Source
Expand description

Pure builders for the Postgres export/import client invocation (argv + PG* env); the credential non-leak rule (password in env, never argv) lives here. Pure builders for the SQL export/import client invocation (Postgres + MySQL) that the driver runs inside run_ephemeral: the argv and the process environment.

§The credential non-leak rule lives here

The password rides in an environment variable (PGPASSWORD for Postgres, MYSQL_PWD for MySQL), NEVER in argv. Both argv and the container environment are visible to a privileged docker inspect, but argv leaks far more broadly — it shows in every process listing (ps, /proc/<pid>/cmdline) inside and outside the container, to any local observer, no daemon privilege required — whereas the container environment is only reachable with daemon/inspect access. Env is therefore the smaller exposure (not zero), and it is the right choice over argv. No DSN string is assembled at all: the discrete PG* / MYSQL* connection variables connect the client, so there is no connection string to accidentally format! into a log. The only secret is the password env var.

§--data-only vs full

--data-only emits/restores ONLY the table data; the target keeps its OWN migrated schema (Phase 1 is data-only: app data, no identity/RBAC/routing). A full export carries schema + data. --no-owner/--no-privileges keep a restore from trying to reassign ownership/ACLs across environments, and pg_restore --exit-on-error makes a failed object abort loudly rather than leave a half-restored database.

Kept pure so the data-only divergence and the cred-placement invariant are unit-mutation-gated in the merge gate.

Structs§

MysqlConnection
A resolved MySQL connection target for the client. The password goes in MYSQL_PWD (the env the mysql/mysqldump clients read), never argv.
PgConnection
A resolved Postgres connection target for the client. Assembled by the driver from the sealed-credential unseal + the resolved replica endpoint; consumed only to emit the PG* environment.
SqlInvocation
A fully-built client invocation: the argv (no credential) + the environment (the credential), ready to hand to run_ephemeral(image, argv, env, …).

Functions§

mysql_admin_invocation
Build a mysql invocation that runs trusted, we-generate-it SQL fed on stdin — the SUPERUSER / maintenance side of the inc2 mysql shadow split (Stage D): CREATE DATABASE <shadow>, the atomic RENAME TABLE swap, DROP DATABASE, and the information_schema table enumeration the swap is built from. No default database is named (so CREATE DATABASE works and every object is schema-qualified in the SQL we build), -N --batch give header-less, tab-separated output for the enumeration query. Host/port/user explicit; password in MYSQL_PWD.
mysql_restore_invocation
Build the mysql invocation for an IMPORT (reads the SQL dump from stdin). Host/port/ user are explicit (conn_args) so the client connects over TCP, not the local socket. A FULL bundle’s dump carries its own USE <db> (from --databases), so no positional db is needed; a --data-only dump has none, so the target <db> is named on the command line. The database name is NOT a credential, so passing it in argv is fine.
mysql_shadow_invocation
Build the mysql invocation that applies the attacker-crafted tables-only dump into a pre-created SHADOW database by NAME (inc2 Stage D) — the UNTRUSTED side of the atomic-shadow split. Meant to run as the TARGET PROJECT’S own NON-SUPERUSER role (the driver resolves that credential) so a crafted statement needing elevated privileges (LOAD DATA INFILE, INTO OUTFILE, creating a LANGUAGE-escalating routine) fails at apply. The dump (which carries NO USE) is fed on stdin and lands in shadow_db because it is named as the default database positionally. Host/port/user explicit; password in MYSQL_PWD; shadow_db is a driver-derived identifier (not a credential), so argv is correct.
mysqldump_invocation
Build the mysqldump invocation for an EXPORT. --single-transaction takes a consistent snapshot without locking (InnoDB); --no-tablespaces avoids the PROCESS privilege requirement. Host/port/user are explicit (conn_args) because mysqldump ignores MYSQL_HOST. A FULL dump emits schema + data under --databases <db> (so the stream carries CREATE DATABASE/USE); --data-only emits only the rows for <db> (--no-create-info), restored into the target’s existing schema. No --connect-timeout: mysqldump does not register it (unknown variable); the overall ephemeral-run timeout bounds a stuck dump instead.
mysqldump_tables_only_invocation
Build the tables-only FULL mysqldump for the inc2 chunked/shadow path (Stage D). Unlike the inc1 FULL dump (mysqldump_invocation with --databases <db>, which emits CREATE DATABASE/USE <original> and so TARGETS THE ORIGINAL NAME), this dumps the db’s TABLES ONLY — a positional <db> with NO --databases — so the stream carries CREATE TABLE + data and NO CREATE DATABASE/USE. That lets mysql <shadow> (mysql_shadow_invocation) apply it into a freshly-created shadow database whose name differs from the source. --single-transaction takes a consistent InnoDB snapshot without locking; --no-tablespaces avoids the PROCESS privilege. Host/port/user are explicit (mysqldump ignores MYSQL_HOST); the password stays in MYSQL_PWD.
pg_dump_invocation
Build the pg_dump invocation for an EXPORT. Custom format (-Fc): compressed and the natural input to pg_restore. --data-only emits only the data AND EXCLUDES the host-owned migration ledger’s rows (boatramp_migrations.*): the ledger is a schema INSIDE the tenant database, so a plain --data-only dump would carry its rows and a pg_restore --data-only --exit-on-error into the already-migrated target (the matching-fingerprint case — the PRIMARY use) would hit a primary-key conflict on the ledger and abort. Excluding it keeps the target’s own boatramp_migrations ledger intact (the stated property).
pg_restore_invocation
Build the pg_restore invocation for an IMPORT (reads the custom-format dump from stdin). --data-only restores only the data into the target’s existing migrated schema; --exit-on-error aborts loudly on the first failed object. Unlike psql/ pg_dump, pg_restore does NOT infer the target from PGDATABASE — without -d (restore into a database) or -f (emit a script) it refuses with “one of -d/–dbname and -f/–file must be specified”; so the target database is named with -d (the host/ port/user/password still come from the env, and the db name is not a credential).
pg_restore_shadow_invocation
Build the pg_restore invocation that applies the attacker-crafted bundle dump into a pre-created SHADOW database (inc2 Stage C) — the UNTRUSTED side of the atomic-shadow split.
psql_invocation
Build a psql invocation that runs one trusted, we-generate-it DDL/utility statement (inc2 Stage C). This is the SUPERUSER / maintenance side of the atomic-shadow split: it runs ONLY our own generated control SQL — CREATE DATABASE <shadow>, pg_terminate_backend, the ALTER DATABASE … RENAME swap, DROP DATABASE — never a byte of the attacker-crafted bundle dump (that is applied by pg_restore_shadow_invocation as the NON-superuser target role).