standardize every Node-based Dockerfile in ~/ on FROM node:24-alpine AND
#15
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
2026-05-12 — fleet chore: standardize every Node-based
Dockerfilein~/onFROM node:24-alpineANDapk add --no-cache … gitso the build image can resolvenpmgit+https://dependencies and so we stop tripping npm 10.9's EBADPLATFORM trap on nested platform-specific optional depsMotivation. Over the last 24 hours four projects (authd, buchinese, nanodrop, inventory) shipped a sqlite-migrate adoption PR and four deploys went red on the same root cause: their
node:*-alpinebuild image doesn't shipgit, sonpm cicouldn't resolvebchen-sqlite-migrate@git+https://gitea.bchen.dev/brendan/sqlite-migrate.git#v0.1.0and printed a misleading "tarball … seems to be corrupted" warning before exiting withENOENT spawn git. The fixes have been (or are being) applied one-by-one as bugs surface — authd PR #16 (gitadded, base already on 24), nanodrop PR #10 (bumped to 24 +gitadded), buchinese pending, inventory pending. dashcam and movement haven't tripped the bug yet because they don't currently consume anygit+https://dep, but they have the same latent vulnerability and will fire the next time any of them adopts sqlite-migrate or any other private-Gitea-URL dep.Separately, the
node:22-alpinebase ships npm 10.9, which has a documented bug where nested@esbuild/*platform-specific optional deps (introduced by e.g. vitest 4.x) are misclassified as required and causeEBADPLATFORMfor@esbuild/aix-ppc64on linux/x64 builds. authd already documented this and bumped tonode:24-alpine(npm 11.x); buchinese is currently tripping the bug for real.Current state (snapshot 2026-05-12 after
git fetchagainstorigin/mainfor each project; verified via~/<repo>/Dockerfile):git?git+https://?node:24-alpineapk add --no-cache python3 make g++ gitnode:22-alpineapk add --no-cache python3 make g++node:22-alpineapk add --no-cache python3 make g++node:24-alpineapk add --no-cache python3 make g++ gitnode:22-alpineapk add --no-cache ffmpeg python3 make g++node:20-alpineapk add --no-cache python3 make g++Scope. Bring every project in the table to the canonical shape:
FROM node:24-alpineplusgitappended to its existing apk install line (preserving any project-specific extras like dashcam'sffmpeg). Six PRs, one per project. Four of them (buchinese, inventory, dashcam, movement) actually need changes; two (authd, nanodrop) already match the target — implementer should verify and skip-with-note rather than ship a no-op PR.For each project requiring a change:
~/<repo>/Dockerfile:1and theRUN apk addline — typically line 3 or 4). Two-line diff: bump base if it's not alreadynode:24-alpine, appendgitto the apk install if it's not there. Preserve project-specific apk extras (dashcam:ffmpeg; future projects may addimagemagick,curl, etc.).npm ciagainst a cleannode_modulessucceeds.tsc --noEmitclean.npm run build(if a build step exists) clean.npm testorvitest run) green.No expected behavior changes; the diff is build-environment-only, so test-count-delta should be zero.
docker build .can't be exercised inside the sandbox (no docker daemon socket reachable, same caveat as the existing sqlite-migrate-adoption PRs). Deferred to the first prod deploy on the new image.~/roles/_sub-claude-rules.md): branchchore/dockerfile-node24-and-git, singlechore:commit, auto-merge via the Gitea sync-from-main precondition. Refactor pass: noop on a two-line diff. Security pass: zero in scope (build-time dependency change; the runtime image gainsgitbut no application code useschild_process/spawn/execto invoke it on user input, so the footgun is purely "if you already have RCE you also have git").Dependency-compatibility audit (so implementer doesn't have to redo it per project): every project in the table runs the same general TypeScript/Node stack —
better-sqlite3,fastify,tsx,vitest— and authd's PR #15/#16 confirmed all of them ship node-24 prebuilds (better-sqlite3@12.6.2,bcrypt@6.0.0,fastify@5.7.4,tsx@4.21.0,vitest@4.0.18). nanodrop PR #10 reconfirmed the same. movement is currently onnode:20-alpine(oldest in the fleet) — itsbetter-sqlite3and other native deps may need to be bumped to node-24-compatible versions; ifnpm ciafter the base bump fails on a native-dep prebuild, ABANDON for movement specifically and re-file as a movement-only sub-item so the dep bumps can be handled separately. The other four are guaranteed-compatible per the prior PRs.Acceptance.
Dockerfilein~/readsFROM node:24-alpineAND itsRUN apk addline includesgit.main(re-run of latest, or fresh trivial commit) reachessuccess. NoEBADPLATFORM, no "tarball … seems to be corrupted", noENOENT spawn git.npm ciresolution of any futuregit+https://dep works fleet-wide without per-project Dockerfile patching.~/bugs.md(buchinese, inventory — both filed 2026-05-12) become moot once this chore lands; bug-fixer should ABANDON them with a note pointing at the chore's merge commits.Future-projects rule. A standing rule has been added to
~/.claude/CLAUDE.md("Node + Alpine Docker base images —node:24-alpine+git") so every new Node-based project the user (or any Claude session) bootstraps starts with the canonical Dockerfile shape. That rule lives next to the existing iOS-16px-font-size standing rule — same template (file a retrofit chore for current fleet, then add a standing rule to prevent regression for everything new).Filer notes.
ffmpeg— verify theapk addline preservation), movement last (oldest base, riskiest dep audit). authd and nanodrop are no-ops.