Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ jobs:
- { name: clock, context: images/clock, file: images/clock/Dockerfile }
- { name: shim, context: images/shim, file: images/shim/Dockerfile }
- { name: node18, context: images/node18, file: images/node18/Dockerfile, content_tag: true }
- { name: node22, context: images/node22, file: images/node22/Dockerfile, content_tag: true }
- { name: node24, context: images/node24, file: images/node24/Dockerfile, content_tag: true }
steps:
- uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ jobs:
# Tool images ship at the release tag; node images ship at a content
# hash of their Dockerfile (images/content-tag.sh), so list each at
# the tag it is actually published under.
for img in operator console clone copier du cleanup clock shim node18 node24; do
for img in operator console clone copier du cleanup clock shim node18 node22 node24; do
case "$img" in
node18 | node24) tag="$(bash images/content-tag.sh "$img")" ;;
node18 | node22 | node24) tag="$(bash images/content-tag.sh "$img")" ;;
*) tag="${{ github.ref_name }}" ;;
esac
echo "- \`ghcr.io/toggle-corp/toggle-web-baker-$img:$tag\`"
Expand Down
4 changes: 2 additions & 2 deletions deploy/helm/toggle-web-baker/snapshots/console.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ data:
clock: "ghcr.io/toggle-corp/toggle-web-baker-clock:0.1.1"
shim: "ghcr.io/toggle-corp/toggle-web-baker-shim:0.1.1"
nginx: "docker.io/nginxinc/nginx-unprivileged:1.27-alpine"
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"22":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node22:22-85c87694aa15","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
defaultSetupCommands: {"pnpm":["pnpm","install","--frozen-lockfile"],"yarn":["yarn","install","--frozen-lockfile"]}
phaseResources:
cpu:
Expand Down Expand Up @@ -1824,7 +1824,7 @@ spec:
metadata:
annotations:
# Roll the operator pod whenever the config ConfigMap content changes.
checksum/config: 6e2048b45f97f17109329c486ed68a91eaeabece1fdf92518d3ed76c94fb0e47
checksum/config: 8f954e32befb33bb8723f59e345f5775032b6a8f807b1c5d11c4b1e64cd48179
labels:
app.kubernetes.io/name: toggle-web-baker
app.kubernetes.io/instance: release-name
Expand Down
4 changes: 2 additions & 2 deletions deploy/helm/toggle-web-baker/snapshots/defaults.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ data:
clock: "ghcr.io/toggle-corp/toggle-web-baker-clock:0.1.1"
shim: "ghcr.io/toggle-corp/toggle-web-baker-shim:0.1.1"
nginx: "docker.io/nginxinc/nginx-unprivileged:1.27-alpine"
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"22":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node22:22-85c87694aa15","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
defaultSetupCommands: {"pnpm":["pnpm","install","--frozen-lockfile"],"yarn":["yarn","install","--frozen-lockfile"]}
phaseResources:
cpu:
Expand Down Expand Up @@ -1565,7 +1565,7 @@ spec:
metadata:
annotations:
# Roll the operator pod whenever the config ConfigMap content changes.
checksum/config: 19e73f5ec2d171b77a7cd7378ff680ca43b7bda04a2b7a5d6abd80e6d256007d
checksum/config: 5a399fc96a00d17f1e4f48cda3bbb188733b1f65a47ae96814d00f6561ddf2ac
labels:
app.kubernetes.io/name: toggle-web-baker
app.kubernetes.io/instance: release-name
Expand Down
4 changes: 2 additions & 2 deletions deploy/helm/toggle-web-baker/snapshots/git-auth.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ data:
clock: "ghcr.io/toggle-corp/toggle-web-baker-clock:0.1.1"
shim: "ghcr.io/toggle-corp/toggle-web-baker-shim:0.1.1"
nginx: "docker.io/nginxinc/nginx-unprivileged:1.27-alpine"
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"22":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node22:22-85c87694aa15","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
defaultSetupCommands: {"pnpm":["pnpm","install","--frozen-lockfile"],"yarn":["yarn","install","--frozen-lockfile"]}
phaseResources:
cpu:
Expand Down Expand Up @@ -1588,7 +1588,7 @@ spec:
metadata:
annotations:
# Roll the operator pod whenever the config ConfigMap content changes.
checksum/config: e7fe5477af01b461ba41a411918a9bdb01fa31a96f9b7c0dcb78a1d7a5172a3d
checksum/config: 19906f02c67c80fa8143b84f0b52347b0f518e6a3c6af799981890e3d9313be8
labels:
app.kubernetes.io/name: toggle-web-baker
app.kubernetes.io/instance: release-name
Expand Down
4 changes: 2 additions & 2 deletions deploy/helm/toggle-web-baker/snapshots/monitoring.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ data:
clock: "ghcr.io/toggle-corp/toggle-web-baker-clock:0.1.1"
shim: "ghcr.io/toggle-corp/toggle-web-baker-shim:0.1.1"
nginx: "docker.io/nginxinc/nginx-unprivileged:1.27-alpine"
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"22":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node22:22-85c87694aa15","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
defaultSetupCommands: {"pnpm":["pnpm","install","--frozen-lockfile"],"yarn":["yarn","install","--frozen-lockfile"]}
phaseResources:
cpu:
Expand Down Expand Up @@ -1595,7 +1595,7 @@ spec:
metadata:
annotations:
# Roll the operator pod whenever the config ConfigMap content changes.
checksum/config: 19e73f5ec2d171b77a7cd7378ff680ca43b7bda04a2b7a5d6abd80e6d256007d
checksum/config: 5a399fc96a00d17f1e4f48cda3bbb188733b1f65a47ae96814d00f6561ddf2ac
labels:
app.kubernetes.io/name: toggle-web-baker
app.kubernetes.io/instance: release-name
Expand Down
4 changes: 2 additions & 2 deletions deploy/helm/toggle-web-baker/snapshots/no-crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ data:
clock: "ghcr.io/toggle-corp/toggle-web-baker-clock:0.1.1"
shim: "ghcr.io/toggle-corp/toggle-web-baker-shim:0.1.1"
nginx: "docker.io/nginxinc/nginx-unprivileged:1.27-alpine"
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
nodeImages: {"18":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node18:18-436d743e3c1c","runAsUser":1000},"22":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node22:22-85c87694aa15","runAsUser":1000},"24":{"image":"ghcr.io/toggle-corp/toggle-web-baker-node24:24-cddf3de62036","runAsUser":1000}}
defaultSetupCommands: {"pnpm":["pnpm","install","--frozen-lockfile"],"yarn":["yarn","install","--frozen-lockfile"]}
phaseResources:
cpu:
Expand Down Expand Up @@ -325,7 +325,7 @@ spec:
metadata:
annotations:
# Roll the operator pod whenever the config ConfigMap content changes.
checksum/config: 6e2048b45f97f17109329c486ed68a91eaeabece1fdf92518d3ed76c94fb0e47
checksum/config: 8f954e32befb33bb8723f59e345f5775032b6a8f807b1c5d11c4b1e64cd48179
labels:
app.kubernetes.io/name: toggle-web-baker
app.kubernetes.io/instance: release-name
Expand Down
4 changes: 4 additions & 0 deletions deploy/helm/toggle-web-baker/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ operator:
repository: ghcr.io/toggle-corp/toggle-web-baker-node18
tag: "18-436d743e3c1c"
runAsUser: 1000
"22":
repository: ghcr.io/toggle-corp/toggle-web-baker-node22
tag: "22-85c87694aa15"
runAsUser: 1000
"24":
repository: ghcr.io/toggle-corp/toggle-web-baker-node24
tag: "24-cddf3de62036"
Expand Down
7 changes: 6 additions & 1 deletion images/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
REGISTRY ?= ghcr.io/toggle-corp/toggle-web-baker
TAG ?= dev

IMAGES := clone copier du cleanup clock shim node18 node24
IMAGES := clone copier du cleanup clock shim node18 node22 node24

# ---- pinned base image digests (mirror of the FROM lines) -------------------
CLONE_BASE := alpine/git@sha256:c0280cf9572316299b08544065d3bf35db65043d5e3963982ec50647d2746e26
Expand All @@ -26,6 +26,7 @@ DU_BASE := alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491
CLEANUP_BASE := node@sha256:813a7480f28fdadac1f7f5c824bcdad435b5bc1322a5968bbbdef8d058f9dff4
CLOCK_BASE := alpine@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d
NODE18_BASE := node@sha256:8d6421d663b4c28fd3ebc498332f249011d118945588d0a35cb9bc4b8ca09d9e
NODE22_BASE := node@sha256:16e22a550f3863206a3f701448c45f7912c6896a62de43add43bb9c86130c3e2
NODE24_BASE := node@sha256:a0b9bf06e4e6193cf7a0f58816cc935ff8c2a908f81e6f1a95432d679c54fbfd

.PHONY: build $(IMAGES) test digests
Expand Down Expand Up @@ -55,6 +56,9 @@ shim:
node18:
docker build -t $(REGISTRY)-node18:$(TAG) ./node18

node22:
docker build -t $(REGISTRY)-node22:$(TAG) ./node22

node24:
docker build -t $(REGISTRY)-node24:$(TAG) ./node24

Expand All @@ -75,4 +79,5 @@ digests:
@echo "cleanup: $(CLEANUP_BASE)"
@echo "clock: $(CLOCK_BASE)"
@echo "node18: $(NODE18_BASE)"
@echo "node22: $(NODE22_BASE)"
@echo "node24: $(NODE24_BASE)"
47 changes: 47 additions & 0 deletions images/node22/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# node22 -- Node.js 22 base for user frontend builds.
#
# Trusted, platform-owned base image the operator runs for a user build when
# spec.nodeVersion selects node 22. The official node:22-alpine already ships a
# numeric `node` user (UID 1000), so no user is created here. Adds bash (the
# phase entrypoints are bash) and git (submodule/lockfile flows), and enables
# corepack so BOTH the yarn and pnpm shims work. Pinned by digest.
FROM node@sha256:16e22a550f3863206a3f701448c45f7912c6896a62de43add43bb9c86130c3e2

# corepack's per-manager version cache. The operator runs this image with
# readOnlyRootFilesystem and injects HOME=/work (a writable emptyDir), so
# corepack's default (~/.cache under HOME) would be an EMPTY dir at runtime --
# corepack would then try to DOWNLOAD a package manager (and mkdir there),
# which fails with EROFS on the read-only root. Pinning COREPACK_HOME to a fixed,
# image-baked path decouples the cache from HOME: the versions pre-activated
# below are found offline and read-only.
ENV COREPACK_HOME=/opt/corepack
# corepack's default, when a project has no packageManager field, is to WRITE one
# into package.json. The operator now runs clone under the build phase's UID, so
# the checkout is WRITABLE by this toolchain (enabling in-tree codegen) — meaning
# that auto-pin would silently SUCCEED, mutating the user's committed manifest
# with a non-reproducible packageManager pin. Disable it: the toolchain may write
# BUILD ARTEFACTS into the tree, but must not rewrite the user's source manifest.
ENV COREPACK_ENABLE_AUTO_PIN=0

# bash for the phase entrypoints; git for repo/submodule and lockfile flows;
# build-base + python3 for node-gyp (native addons some deps compile on install --
# this is the "anything else from cimg/node" part: cimg bundles build tools).
# corepack enable installs the yarn/pnpm shims into /usr/local/bin, REPLACING the
# bundled yarn binary with a shim -- so yarn too must be pre-activated or it will
# try to download at runtime. Pre-activate pnpm 10.x (supports node 22) + classic
# yarn into COREPACK_HOME (as root, world-readable) so both resolve offline at
# runtime regardless of the injected HOME.
#
# The pre-activated pnpm version must MATCH what target apps pin via their
# package.json `packageManager` field: corepack honours that pin EXACTLY and, on a
# mismatch, tries to DOWNLOAD the pinned version into COREPACK_HOME -> EROFS under
# the operator's readOnlyRootFilesystem. 10.34.5 tracks the current mapswipe-website
# pin (its e2e is node22's primary real-app validation); bump this when apps move.
RUN apk add --no-cache bash git build-base python3 \
&& corepack enable \
&& corepack prepare yarn@1.22.22 --activate \
&& corepack prepare pnpm@10.34.5 --activate

# The node:alpine base already provides the numeric `node` user (UID 1000); run
# as it for sane local runs. The operator overrides runAsUser at runtime anyway.
USER node
20 changes: 20 additions & 0 deletions images/node22/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# node22

Node.js 22 base image for user frontend builds.

## Contract

| | |
|---|---|
| **Runs as** | build-pod init/main container, `USER node` (UID 1000) |
| **Base** | `node:22-alpine` pinned by digest |
| **Selected via** | `spec.pipeline.nodeVersion` on the App (picks node 22) |
| **Adds** | `bash` (phase entrypoints are bash), `git` (repo/submodule and lockfile flows), `build-base` + `python3` (node-gyp native addons), `corepack` with **yarn 1.22.22 + pnpm 10.34.5** pre-activated |

The official `node:22-alpine` already provides a numeric `node` user (UID 1000),
so no user is created; the image ends with `USER node` for sane local runs. The
operator overrides `runAsUser` at runtime.

`COREPACK_HOME` is baked to a fixed path with yarn+pnpm pre-activated, so both
package managers resolve **offline** under the operator's `readOnlyRootFilesystem`
+ injected `HOME=/work` — no runtime download.
2 changes: 1 addition & 1 deletion images/test/check_images_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ case "$out" in *"clock"*) ok "missing-in-matrix: mentions clock" ;; *) no "missi

# ---- 4. missing-in-release-body: drop node24 from the for-loop list --------
rel_no_node24="$TMP/release-no-node24.yml"
sed 's/for img in operator console clone copier du cleanup clock shim node18 node24;/for img in operator console clone copier du cleanup clock shim node18;/' \
sed 's/for img in operator console clone copier du cleanup clock shim node18 node22 node24;/for img in operator console clone copier du cleanup clock shim node18 node22;/' \
"$REPO/.github/workflows/release.yml" >"$rel_no_node24"
rc=0
out="$(RELEASE_YML="$rel_no_node24" bash "$CHECK" 2>&1)" || rc=$?
Expand Down
Loading
Loading