From 9faa46ff56b0f8f45522e56f11606acfb53c5ee2 Mon Sep 17 00:00:00 2001 From: os-steve Date: Sat, 5 Sep 2026 23:26:11 +0000 Subject: [PATCH] ci(docker): assert the SQL drivers are in the published runtime image The smoke step proved the CLI resolved but nothing asserted that `pg` and `mysql2` -- which docker/Dockerfile installs and docker/README.md publishes as a maintained promise -- are actually in the built image. The in-repo `check:docs-image-tag` pin cannot see that: it compares the install line against the published table, and both would still agree if the drivers vanished from the image. The probe resolves from inside the global tree (`-w`), which is both how the real boot path resolves the drivers and the only spelling that discriminates: `npm install -g` writes to /usr/local/lib/node_modules, which is not on `require()`'s search path from the image's WORKDIR (/srv/app), and the node:22-slim base sets no NODE_PATH. Verified in both directions against purpose-built images before landing: green with the drivers present, red (`Cannot find module 'pg'`) without. Claude-Session: https://claude.ai/code/session_01PU9zBGbH2s2ZtxSyu963M3 Co-authored-by: Claude --- .github/workflows/docker-publish.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index ecf44480ff..c9edc62e20 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -97,8 +97,29 @@ jobs: # `os --version` proves the CLI resolved, installed, and runs on the # pushed image; a boot test needs an artifact + DB and belongs to the # examples/e2e suites, not here. + # + # The `require()` line proves the SQL drivers are actually IN the built + # image. `check:docs-image-tag` cannot see that: it compares the + # Dockerfile install line against README.md's published table, and both + # would still agree if the drivers vanished from the image. The class + # has already cost a boot once -- docker/Dockerfile records that a tree + # without `pg` "died at boot on `Cannot find module 'pg'`", which is why + # the install line exists. `require()` needs no artifact and no + # database, so it stays on the right side of the same line drawn above. + # + # `-w` is load-bearing, not incidental. `npm install -g` puts the + # drivers in /usr/local/lib/node_modules, which is NOT on `require()`'s + # search path from this image's WORKDIR (/srv/app): node's global + # folders are $PREFIX/lib/node, and the node:22-slim base sets no + # NODE_PATH. Run from /srv/app the probe fails on a CORRECT image, so + # it would be a constant red rather than a check. Resolving from inside + # the global tree is also how the real boot path resolves them -- + # driver-sql lives there too. Do not "simplify" this to a bare + # `docker run`; verified in both directions before it landed. env: VERSION: ${{ steps.version.outputs.version }} run: | docker pull "$IMAGE:$VERSION" docker run --rm "$IMAGE:$VERSION" os --version + docker run --rm -w /usr/local/lib/node_modules "$IMAGE:$VERSION" \ + node -e "require('pg'); require('mysql2')"