fix(docker): bake pnpm via npm to remove Corepack runtime downloads (GRO-1981) #129
@@ -156,3 +156,32 @@ jobs:
|
|||||||
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/reset:latest' || '' }}
|
${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/reset:latest' || '' }}
|
||||||
cache-from: type=registry,ref=git.farh.net/groombook/cache:reset
|
cache-from: type=registry,ref=git.farh.net/groombook/cache:reset
|
||||||
cache-to: type=registry,ref=git.farh.net/groombook/cache:reset,mode=max
|
cache-to: type=registry,ref=git.farh.net/groombook/cache:reset,mode=max
|
||||||
|
|
||||||
|
- name: Smoke test seed image (blackhole npmjs.org)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IMAGE="git.farh.net/groombook/seed:${{ steps.version.outputs.tag }}"
|
||||||
|
docker pull "$IMAGE"
|
||||||
|
# GRO-1985: pnpm must be a real binary, not a Corepack shim, and must
|
||||||
|
# not try to reach registry.npmjs.org on invocation.
|
||||||
|
docker run --rm \
|
||||||
|
--add-host registry.npmjs.org:127.0.0.1 \
|
||||||
|
--entrypoint="" \
|
||||||
|
"$IMAGE" \
|
||||||
|
sh -c 'set -e; test "$(which pnpm)" = "/usr/local/bin/pnpm"; pnpm --version'
|
||||||
|
echo "seed image: pnpm resolves to /usr/local/bin/pnpm and runs offline ✓"
|
||||||
|
|
||||||
|
- name: Smoke test reset image (blackhole npmjs.org)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
IMAGE="git.farh.net/groombook/reset:${{ steps.version.outputs.tag }}"
|
||||||
|
docker pull "$IMAGE"
|
||||||
|
# GRO-1985: pnpm must be a real binary, not a Corepack shim, and must
|
||||||
|
# not try to reach registry.npmjs.org on invocation. Validates the
|
||||||
|
# hard requirement from the issue: reset runs offline.
|
||||||
|
docker run --rm \
|
||||||
|
--add-host registry.npmjs.org:127.0.0.1 \
|
||||||
|
--entrypoint="" \
|
||||||
|
"$IMAGE" \
|
||||||
|
sh -c 'set -e; test "$(which pnpm)" = "/usr/local/bin/pnpm"; echo "HOME=$HOME"; pnpm --version'
|
||||||
|
echo "reset image: pnpm resolves to /usr/local/bin/pnpm, HOME=/tmp, runs offline ✓"
|
||||||
|
|||||||
+13
-1
@@ -3,8 +3,12 @@ FROM node:22-alpine AS base
|
|||||||
# invocations of `pnpm` work without DNS access to registry.npmjs.org.
|
# invocations of `pnpm` work without DNS access to registry.npmjs.org.
|
||||||
# The corepack shim delegates to corepack, which re-validates against
|
# The corepack shim delegates to corepack, which re-validates against
|
||||||
# npmjs.org on first use — that fails in air-gapped UAT seed/migrate/reset
|
# npmjs.org on first use — that fails in air-gapped UAT seed/migrate/reset
|
||||||
# Jobs. GRO-1983 / GRO-1889 / GRO-1909.
|
# Jobs. GRO-1983 / GRO-1889 / GRO-1909 / GRO-1981 / GRO-1985.
|
||||||
RUN npm install -g pnpm@9.15.4
|
RUN npm install -g pnpm@9.15.4
|
||||||
|
# Belt-and-braces: disable Corepack's download fallback so that even if a
|
||||||
|
# Corepack shim is somehow invoked at runtime, it will not try to fetch
|
||||||
|
# pnpm from registry.npmjs.org. Belt for the real-binary trousers. GRO-1985.
|
||||||
|
ENV COREPACK_ENABLE_DOWNLOAD_FALLBACK=0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install deps
|
# Install deps
|
||||||
@@ -26,6 +30,8 @@ RUN pnpm --filter @groombook/types build && \
|
|||||||
# Runtime
|
# Runtime
|
||||||
FROM node:22-alpine AS runner
|
FROM node:22-alpine AS runner
|
||||||
RUN npm install -g pnpm@9.15.4
|
RUN npm install -g pnpm@9.15.4
|
||||||
|
# Same defence-in-depth as base: no Corepack fallback. GRO-1985.
|
||||||
|
ENV COREPACK_ENABLE_DOWNLOAD_FALLBACK=0
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
@@ -46,12 +52,18 @@ CMD ["node", "dist/index.js"]
|
|||||||
|
|
||||||
# Migrate stage — runs drizzle-kit migrate against the database
|
# Migrate stage — runs drizzle-kit migrate against the database
|
||||||
FROM builder AS migrate
|
FROM builder AS migrate
|
||||||
|
# pnpm needs a writable HOME for any config/state it writes. With
|
||||||
|
# readOnlyRootFilesystem: true and runAsUser: 1000, /home/node is read-only.
|
||||||
|
# The job pods mount a writable emptyDir at /tmp; point HOME there. GRO-1985.
|
||||||
|
ENV HOME=/tmp
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "migrate"]
|
CMD ["pnpm", "--filter", "@groombook/db", "migrate"]
|
||||||
|
|
||||||
# Seed stage — populates the database with test data
|
# Seed stage — populates the database with test data
|
||||||
FROM builder AS seed
|
FROM builder AS seed
|
||||||
|
ENV HOME=/tmp
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "seed"]
|
CMD ["pnpm", "--filter", "@groombook/db", "seed"]
|
||||||
|
|
||||||
# Reset stage — drops all tables, re-runs migrations, and re-seeds
|
# Reset stage — drops all tables, re-runs migrations, and re-seeds
|
||||||
FROM builder AS reset
|
FROM builder AS reset
|
||||||
|
ENV HOME=/tmp
|
||||||
CMD ["pnpm", "--filter", "@groombook/db", "reset"]
|
CMD ["pnpm", "--filter", "@groombook/db", "reset"]
|
||||||
|
|||||||
Reference in New Issue
Block a user