#236: pin the Node version
All checks were successful
All checks were successful
.node-version (22.15.1) becomes the single authoritative Node version: CI/CD select Node only via node-version-file, every Dockerfile pins node:22.15.1-alpine, and the engines floor in package.json states the same version (open-ended upwards so a newer local Node keeps working — reproducibility rests on images and CI). An early CI step fails on any drift between those places; update procedure in operations.md (Update strategy). Precondition for the reproducibility claim in #219. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
This commit is contained in:
parent
9a43a2f6bb
commit
6a520e27b1
@ -86,7 +86,7 @@ jobs:
|
|||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
@ -58,13 +58,42 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# One authoritative Node version (issue #236): `.node-version` is the
|
||||||
|
# pin; every Dockerfile image tag and the engines floor must match it
|
||||||
|
# exactly, and workflows select Node only through node-version-file.
|
||||||
|
# Raising Node = update .node-version, every `FROM node:` tag and the
|
||||||
|
# engines floor in ONE commit (procedure: docs/architecture/operations.md
|
||||||
|
# §Update strategy). The bracketed grep pattern keeps this step from
|
||||||
|
# matching its own source (same trick as the secret fence above).
|
||||||
|
- name: Node version pin is consistent
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
ver="$(cat .node-version)"
|
||||||
|
echo "pinned Node version: $ver"
|
||||||
|
bad=0
|
||||||
|
for f in apps/*/Dockerfile; do
|
||||||
|
if grep '^FROM node:' "$f" | grep -v "node:${ver}-alpine"; then
|
||||||
|
echo "$f pins a different Node image than node:${ver}-alpine"
|
||||||
|
bad=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if grep -rn "node-version[:] " .gitea/workflows; then
|
||||||
|
echo "workflows must use node-version-file, not a literal version"
|
||||||
|
bad=1
|
||||||
|
fi
|
||||||
|
if ! grep -q "\"node\": \">=${ver}\"" package.json; then
|
||||||
|
echo "package.json engines floor does not match ${ver}"
|
||||||
|
bad=1
|
||||||
|
fi
|
||||||
|
exit "$bad"
|
||||||
|
|
||||||
- name: Set up pnpm
|
- name: Set up pnpm
|
||||||
uses: pnpm/action-setup@v4
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -119,7 +148,7 @@ jobs:
|
|||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -594,7 +623,7 @@ jobs:
|
|||||||
- name: Set up Node.js
|
- name: Set up Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
1
.node-version
Normal file
1
.node-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
22.15.1
|
||||||
@ -1,7 +1,7 @@
|
|||||||
# Build context is the repository root (workspace build):
|
# Build context is the repository root (workspace build):
|
||||||
# docker build -f apps/api/Dockerfile .
|
# docker build -f apps/api/Dockerfile .
|
||||||
|
|
||||||
FROM node:22.15-alpine AS build
|
FROM node:22.15.1-alpine AS build
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
RUN npm install -g pnpm@11
|
RUN npm install -g pnpm@11
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||||
@ -23,7 +23,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/api... \
|
|||||||
&& cp -r apps/api/dist /out/dist \
|
&& cp -r apps/api/dist /out/dist \
|
||||||
&& cp -r /repo/fonts /out/fonts
|
&& cp -r /repo/fonts /out/fonts
|
||||||
|
|
||||||
FROM node:22.15-alpine
|
FROM node:22.15.1-alpine
|
||||||
ARG APP_VERSION=0.0.0-dev
|
ARG APP_VERSION=0.0.0-dev
|
||||||
# Default the data dirs to the writable, node-owned locations created below, so
|
# Default the data dirs to the writable, node-owned locations created below, so
|
||||||
# the image works out of the box even where compose does not set them; compose
|
# the image works out of the box even where compose does not set them; compose
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Build context is the repository root (workspace build):
|
# Build context is the repository root (workspace build):
|
||||||
# docker build -f apps/backup/Dockerfile .
|
# docker build -f apps/backup/Dockerfile .
|
||||||
|
|
||||||
FROM node:22.15-alpine AS build
|
FROM node:22.15.1-alpine AS build
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
RUN npm install -g pnpm@11
|
RUN npm install -g pnpm@11
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||||
@ -14,7 +14,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/backup... \
|
|||||||
&& pnpm --filter @dorfteich/backup deploy --prod --legacy /out \
|
&& pnpm --filter @dorfteich/backup deploy --prod --legacy /out \
|
||||||
&& cp -r apps/backup/dist /out/dist
|
&& cp -r apps/backup/dist /out/dist
|
||||||
|
|
||||||
FROM node:22.15-alpine
|
FROM node:22.15.1-alpine
|
||||||
ARG APP_VERSION=0.0.0-dev
|
ARG APP_VERSION=0.0.0-dev
|
||||||
ENV NODE_ENV=production APP_VERSION=${APP_VERSION} \
|
ENV NODE_ENV=production APP_VERSION=${APP_VERSION} \
|
||||||
# Baked-in volume paths (self-sufficient without compose env, like the
|
# Baked-in volume paths (self-sufficient without compose env, like the
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Build context is the repository root (workspace build):
|
# Build context is the repository root (workspace build):
|
||||||
# docker build -f apps/collab/Dockerfile .
|
# docker build -f apps/collab/Dockerfile .
|
||||||
|
|
||||||
FROM node:22.15-alpine AS build
|
FROM node:22.15.1-alpine AS build
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
RUN npm install -g pnpm@11
|
RUN npm install -g pnpm@11
|
||||||
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json tsconfig.base.json ./
|
||||||
@ -14,7 +14,7 @@ RUN pnpm install --frozen-lockfile --filter @dorfteich/collab... \
|
|||||||
&& pnpm --filter @dorfteich/collab deploy --prod --legacy /out \
|
&& pnpm --filter @dorfteich/collab deploy --prod --legacy /out \
|
||||||
&& cp -r apps/collab/dist /out/dist
|
&& cp -r apps/collab/dist /out/dist
|
||||||
|
|
||||||
FROM node:22.15-alpine
|
FROM node:22.15.1-alpine
|
||||||
ARG APP_VERSION=0.0.0-dev
|
ARG APP_VERSION=0.0.0-dev
|
||||||
ENV NODE_ENV=production APP_VERSION=${APP_VERSION}
|
ENV NODE_ENV=production APP_VERSION=${APP_VERSION}
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Build context is the repository root (workspace build):
|
# Build context is the repository root (workspace build):
|
||||||
# docker build -f apps/web/Dockerfile .
|
# docker build -f apps/web/Dockerfile .
|
||||||
|
|
||||||
FROM node:22.15-alpine AS build
|
FROM node:22.15.1-alpine AS build
|
||||||
ARG APP_VERSION=0.0.0-dev
|
ARG APP_VERSION=0.0.0-dev
|
||||||
WORKDIR /repo
|
WORKDIR /repo
|
||||||
RUN npm install -g pnpm@11
|
RUN npm install -g pnpm@11
|
||||||
|
|||||||
@ -169,6 +169,16 @@ not a copy of the purged page.
|
|||||||
- **Base image / dependency hygiene**: monthly dependency-update story
|
- **Base image / dependency hygiene**: monthly dependency-update story
|
||||||
(renovate-style batch PR); security advisories for pinned images tracked
|
(renovate-style batch PR); security advisories for pinned images tracked
|
||||||
in the release checklist.
|
in the release checklist.
|
||||||
|
- **Toolchain pin (issue #236)**: `.node-version` is the single
|
||||||
|
authoritative Node version. CI/CD select Node exclusively via
|
||||||
|
`node-version-file`, every Dockerfile pins `node:<version>-alpine`, and
|
||||||
|
the `engines.node` floor in `package.json` states the same version
|
||||||
|
(open-ended upwards — a newer local Node keeps working; reproducibility
|
||||||
|
rests on the images and CI, not the laptop). An early CI step fails on
|
||||||
|
any drift between those places. Raising Node (e.g. for a security fix):
|
||||||
|
update `.node-version`, all four Dockerfiles and the engines floor in
|
||||||
|
ONE commit and let CI confirm. pnpm is pinned the same way via
|
||||||
|
`packageManager`.
|
||||||
|
|
||||||
## Capacity & limits (initial values, instance-tunable)
|
## Capacity & limits (initial values, instance-tunable)
|
||||||
|
|
||||||
|
|||||||
@ -255,7 +255,7 @@ fehlten — als Issues angelegt:
|
|||||||
· 1 AT · #234 (M24, I-23)
|
· 1 AT · #234 (M24, I-23)
|
||||||
- [x] `page_links.target_slug`-Residuum nach Purge entscheiden
|
- [x] `page_links.target_slug`-Residuum nach Purge entscheiden
|
||||||
· 0,5 AT · #235 (M24, I-24)
|
· 0,5 AT · #235 (M24, I-24)
|
||||||
- [ ] Node-Version pinnen — Voraussetzung für #219 · 0,5 AT · #236 (M25, I-26)
|
- [x] Node-Version pinnen — Voraussetzung für #219 · 0,5 AT · #236 (M25, I-26)
|
||||||
|
|
||||||
Ohne eigenes Issue: IndexedDB-Kopie auf Endgeräten (I-25) — als
|
Ohne eigenes Issue: IndexedDB-Kopie auf Endgeräten (I-25) — als
|
||||||
Akzeptanzkriterium in #226 (Abgrenzungserklärung) und #231
|
Akzeptanzkriterium in #226 (Abgrenzungserklärung) und #231
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
"description": "Dorfteich — an open-source wiki system with real-time collaboration",
|
"description": "Dorfteich — an open-source wiki system with real-time collaboration",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22.15.1"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@11.9.0",
|
"packageManager": "pnpm@11.9.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user