From ae6acdd0097c5f86b8e70c1470580890689ff3a3 Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Thu, 22 Oct 2026 05:50:49 -0700 Subject: [PATCH] feat: Node.js 24 and 26 images; refuse builds below the Oct 2026 security floor - One install-node.sh replaces install-node{18,20,22}.sh. It fails the build if NodeSource hands back a version below the newest security release for the line (22.23.4 / 24.22.1 / 26.12.1: CVE-2026-111497 Brotli OOB write and 9 others), so a lagging mirror can't ship a vulnerable image silently. 18 and 20 are EOL: they still build, with a warning. - CI matrix adds 24 and 26; fail-fast off so one line can't cancel the rest. Co-Authored-By: Claude Opus 5.5 --- .gitea/workflows/build-push.yaml | 3 ++- CLAUDE.md | 4 ++-- Dockerfile | 2 +- README.md | 8 ++++---- scripts/install-node.sh | 33 ++++++++++++++++++++++++++++++++ scripts/install-node18.sh | 6 ------ scripts/install-node20.sh | 6 ------ scripts/install-node22.sh | 6 ------ 8 files changed, 42 insertions(+), 26 deletions(-) create mode 100755 scripts/install-node.sh delete mode 100755 scripts/install-node18.sh delete mode 100755 scripts/install-node20.sh delete mode 100755 scripts/install-node22.sh diff --git a/.gitea/workflows/build-push.yaml b/.gitea/workflows/build-push.yaml index cc48f9b..9b2059c 100644 --- a/.gitea/workflows/build-push.yaml +++ b/.gitea/workflows/build-push.yaml @@ -9,8 +9,9 @@ jobs: Build-and-Push: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - nodever: [18, 20, 22] + nodever: [18, 20, 22, 24, 26] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/CLAUDE.md b/CLAUDE.md index 1632d67..cb61cb9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -Cloud Node Container (CNOC) is a Docker-based Node.js hosting environment that supports multiple Node.js versions (18, 20, 22) with Nginx reverse proxy, designed for both local development and production deployment. +Cloud Node Container (CNOC) is a Docker-based Node.js hosting environment that supports multiple Node.js versions (18, 20, 22, 24, 26) with Nginx reverse proxy, designed for both local development and production deployment. ## Common Development Commands @@ -63,7 +63,7 @@ docker run -d -p 80:80 -p 443:443 \ - **PROD** (default): Expects external services, optimized for production 3. **Node.js Version Management**: - - Controlled via `NODEVER` environment variable (18, 20, 22) + - Controlled via `NODEVER` environment variable (18, 20, 22, 24, 26) - Each version has dedicated install script in `/scripts/` - PM2 ecosystem configuration adapts to user paths diff --git a/Dockerfile b/Dockerfile index d1a141b..f5ab341 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN chmod +x /scripts/* # Generate self-signed cert, create needed dirs, install Node.js, clean up RUN openssl req -newkey rsa:2048 -nodes -keyout /etc/pki/tls/private/localhost.key -x509 -days 3650 -subj "/CN=localhost" -out /etc/pki/tls/certs/localhost.crt && \ mkdir -p /var/log/nodejs && \ - /scripts/install-node$NODEVER.sh && \ + /scripts/install-node.sh "$NODEVER" && \ rm -rf /tmp/* # Install PM2 globally for process management with minimal footprint diff --git a/README.md b/README.md index 2cf0c03..8a06b80 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Cloud Node Container -This is a base container for running Node.js applications, supporting multiple Node.js versions (18, 20, 22). The default is Node.js 20. The container is based on AlmaLinux 10 and uses Nginx as a reverse proxy with SSL. It is designed for both development and production use. +This is a base container for running Node.js applications, supporting multiple Node.js versions (18, 20, 22, 24, 26). The default is Node.js 20. The container is based on AlmaLinux 10 and uses Nginx as a reverse proxy with SSL. It is designed for both development and production use. **You must have Docker or compatible containerization software running.** @@ -8,7 +8,7 @@ This is a base container for running Node.js applications, supporting multiple N ## What's Included? -- **Multiple Node.js Versions:** 18, 20, 22 (set with `NODEVER` or `-a` flag) +- **Multiple Node.js Versions:** 18, 20, 22, 24, 26 (set with `NODEVER` or `-a` flag) - **PM2 Process Manager:** For production-grade Node.js application management - **Nginx Reverse Proxy:** SSL-enabled reverse proxy with automatic HTTP to HTTPS redirect - **Development Features:** Memcached for sessions, automatic backups, log rotation @@ -227,7 +227,7 @@ When you place your app in `user/app/`, the container automatically: ## Features -- **Multiple Node.js Versions:** 18, 20, 22 (set with `NODEVER` environment variable) +- **Multiple Node.js Versions:** 18, 20, 22, 24, 26 (set with `NODEVER` environment variable) - **Process Management:** PM2 for production-grade Node.js application management - **Reverse Proxy:** Nginx handles SSL termination and proxies requests to Node.js - **WebSockets:** socket.io and `ws` supported out of the box (see [WebSocket Support](#websocket-support-socketio-ws)) @@ -250,7 +250,7 @@ When you place your app in `user/app/`, the container automatically: **Optional:** - `environment` – Set to `DEV` to start Redis and enable development features - `serveralias` – Comma-separated list of alternative hostnames -- `NODEVER` – Node.js version (18, 20, 22) +- `NODEVER` – Node.js version (18, 20, 22, 24, 26) --- diff --git a/scripts/install-node.sh b/scripts/install-node.sh new file mode 100755 index 0000000..f0587d6 --- /dev/null +++ b/scripts/install-node.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# Install Node.js from NodeSource, then refuse a build whose version is +# below the newest security release for that line. NodeSource mirrors can lag +# a release, and without this check a stale mirror ships a vulnerable image +# that looks like a normal successful build. +# usage: install-node.sh +set -euo pipefail +major="${1:?usage: install-node.sh }" +case "$major" in ''|*[!0-9]*) echo "bad Node major: $major" >&2; exit 64;; esac + +# Minimum acceptable version per line. Raise these when Node.js publishes a +# security release. 18 and 20 are end of life and get no fixes upstream. +declare -A MIN=( + [22]=22.23.4 # 2026-10-20 security release (CVE-2026-111497 Brotli, +9) + [24]=24.22.1 + [26]=26.12.1 +) + +wget -qO- "https://rpm.nodesource.com/setup_${major}.x" | bash - +dnf install -y nodejs +npm install -g npm@latest + +have="$(node -p 'process.versions.node')" +case "$have" in "$major".*) ;; *) echo "ERROR: wanted Node $major, got $have" >&2; exit 1;; esac +if [ -n "${MIN[$major]:-}" ]; then + if [ "$(printf '%s\n%s\n' "${MIN[$major]}" "$have" | sort -V | head -1)" != "${MIN[$major]}" ]; then + echo "ERROR: Node $have is below the security floor ${MIN[$major]} for line $major (mirror behind?)" >&2 + exit 1 + fi +else + echo "WARNING: Node $major is end of life; this image gets no Node.js security fixes." >&2 +fi +echo "node $have, npm $(npm --version)" diff --git a/scripts/install-node18.sh b/scripts/install-node18.sh deleted file mode 100755 index 9d15e0c..0000000 --- a/scripts/install-node18.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -wget -qO- https://rpm.nodesource.com/setup_18.x | bash - -dnf install -y nodejs -npm install -g npm@latest -node --version -npm --version \ No newline at end of file diff --git a/scripts/install-node20.sh b/scripts/install-node20.sh deleted file mode 100755 index 0f2c276..0000000 --- a/scripts/install-node20.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -wget -qO- https://rpm.nodesource.com/setup_20.x | bash - -dnf install -y nodejs -npm install -g npm@latest -node --version -npm --version \ No newline at end of file diff --git a/scripts/install-node22.sh b/scripts/install-node22.sh deleted file mode 100755 index 872fc18..0000000 --- a/scripts/install-node22.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -wget -qO- https://rpm.nodesource.com/setup_22.x | bash - -dnf install -y nodejs -npm install -g npm@latest -node --version -npm --version \ No newline at end of file