Skip to content

Task 11: a disposable PostgreSQL 16 environment for integration testing - #11

Merged
roachitect-aman merged 1 commit into
mainfrom
task-11-docker-environment
Aug 25, 2026
Merged

Task 11: a disposable PostgreSQL 16 environment for integration testing#11
roachitect-aman merged 1 commit into
mainfrom
task-11-docker-environment

Conversation

@roachitect-aman

Copy link
Copy Markdown
Contributor

Adds the Docker/Podman environment the integration suite will run against, plus the docs and guard tests that keep it from leaking anything.

What's here

docker-compose.postgres-test.ymlpostgres:16 on a named volume, pg_stat_statements preloaded, published on 127.0.0.1 only, with a pg_isready health check so --wait blocks until the server actually answers. Every credential is a ${...} substitution from the gitignored .env.test.local. The file holds no password, no port, and no connection string, so it is safe to read in a public repository.

Substitutions are ${VAR:?message}, never ${VAR:-default}. A default lets a typo in the env file start a server with credentials nobody chose, and the failure then surfaces somewhere less obvious than the mistake.

testdata/postgres-test-init.sqlCREATE EXTENSION pg_stat_statements, mounted read-only at /docker-entrypoint-initdb.d/ instead of being a documented manual step after start. The profiler degrades gracefully when the extension is absent, so a skipped step would leave the integration suite quietly exercising the degraded path rather than the one it means to cover. The cost is that it only runs against an empty volume, which is why down -v gets its own section in the docs.

docs/TESTING.md — start, health check, run, stop, reset. Every command passes --env-file, because interpolation runs for ps and exec and down too, not just up. The health check expands credentials inside the container, so none reaches shell history or a host process's command line.

There is deliberately no committed example env file. That is where a real connection string eventually gets pasted, and no reviewer reading the diff could tell the value was supposed to be fake. The doc lists variable names in a table instead.

A real bug, found by running it

The first run against the live container failed at pg_dump exited with status 1.

PG_DUMP_ARGS was being spliced in ahead of --version, producing pg_dump -w --version. pg_dump handles --version by comparing argv[1] before getopt runs, and its long-option table has no entry for it — so anything ahead of it, even a harmless -w, makes it an unrecognized option and pg_dump exits 1 with nothing but a "try --help" hint.

The unit test asserted the wrong argv and the fake matched on \"--version\" in argv, so neither noticed. Now [pg_dump, \"--version\"] exactly, with both tests corrected. This is precisely the class of bug the Docker environment exists to catch, and it showed up before the integration suite that was meant to catch it.

Guard tests

TestComposeSecrecy asserts the properties rather than trusting review: no :// in the Compose file, no token key, every credential field a bare ${...}, no substitution carrying a default, every published port prefixed 127.0.0.1:, the preload present, .env.test.local gitignored, no tracked .env* file, and no credentialed URL in the docs.

Each was mutation-tested. Rebinding to 0.0.0.0, hardcoding a password, switching to ${VAR:-postgres}, dropping the preload, and pasting a URL into a comment all turn the suite red.

Verified

Against the live container: nine bundle entries, no warnings, server_version_num 160015, stats_reset captured. Host listener confirmed as 127.0.0.1.55432 only — a connection to the machine's LAN address is refused.

Runtime was Podman 5.8.1 behind a docker CLI shim with podman-compose. The Compose file uses no Docker-specific extension, and the docs say so rather than assuming Docker Desktop.

363 tests OK
--check-safety: OK (14 SQL constants checked)
ruff check: All checks passed
3.9 grammar: both files parse

docker-compose.postgres-test.yml brings up postgres:16 on a named volume with
pg_stat_statements preloaded, published on 127.0.0.1 only. Every credential is
a ${...} substitution from .env.test.local, which is gitignored; the Compose
file holds no password, no port, and no connection string, so it is safe to
read in a public repository.

Substitutions use ${VAR:?message} rather than a default value. A default lets a
typo in the env file start a server with credentials nobody chose, and the
failure then surfaces somewhere less obvious than the mistake.

CREATE EXTENSION pg_stat_statements runs from testdata/postgres-test-init.sql
at initdb time rather than as a documented manual step. The profiler degrades
gracefully when the extension is absent, so a skipped step would leave the
integration suite quietly exercising the degraded path instead of the one it
means to cover.

TestComposeSecrecy asserts these properties rather than trusting review: no
connection string in the Compose file, every credential field a bare ${...},
every published port bound to loopback, the env file ignored, no tracked .env*
file, and no credentialed URL in the docs. Rebinding to 0.0.0.0, hardcoding a
password, or dropping the preload each turns the suite red.

Running the tool against the live container found a real bug. PG_DUMP_ARGS was
spliced in ahead of --version, producing `pg_dump -w --version`. pg_dump
handles --version by comparing argv[1] before getopt runs and has no entry for
it in the long-option table, so anything ahead of it -- even a harmless -w --
makes it an unrecognized option and pg_dump exits 1 with only a "try --help"
hint. The unit test asserted the wrong argv and the fake matched on
`"--version" in argv`, so neither noticed. Fixed to `[pg_dump, "--version"]`,
with both tests corrected.

docs/TESTING.md documents start, health check, run, stop, and reset. Every
command passes --env-file, because interpolation runs for ps and exec and down
too. The health check expands credentials inside the container, so none reaches
shell history. There is deliberately no committed example env file: that is
where a real connection string eventually gets pasted, and no reviewer reading
the diff could tell the value was meant to be fake.

Verified end to end against the container: nine bundle entries, no warnings,
server_version_num 160015, stats_reset captured, and the host listening on
127.0.0.1 only. Runtime was Podman behind a docker shim; the Compose file uses
no Docker-specific extension.

363 tests pass; --check-safety, ruff, and the 3.9 grammar check are clean.

Co-Authored-By: roachdev-claude <roachdev-claude-bot@cockroachlabs.com>
@roachitect-aman
roachitect-aman merged commit 1aff6d2 into main Aug 25, 2026
7 checks passed
@roachitect-aman
roachitect-aman deleted the task-11-docker-environment branch August 25, 2026 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant