chore(docker): clear most CVEs in published image (npm/pnpm/uuid + drop curl) (#7674)

* chore(docker): clear most CVEs in published image — npm/pnpm/uuid + drop curl

Cuts published-image vulnerabilities from 18 (4H/13M/1L) across 8 packages
to 12 (2H/9M/1L) across 3 packages. The remaining three (curl/libcurl,
git, busybox) are all upstream Alpine 3.23 packages with "not fixed"
status — libcurl is pulled in transitively by git and cannot be
removed independently.

Changes:

- Provision pnpm via corepack instead of `npm install -g pnpm`, then
  remove the bundled npm. The base image's npm@10.9.7 ships old
  transitives (picomatch 4.0.3 → CVE-2026-33671/33672, brace-expansion
  2.0.2 → CVE-2026-33750) that we don't otherwise need at runtime;
  corepack handles pnpm directly without npm. Fixes 1H + 1M.

- Bump PnpmVersion 10.28.2 → 10.33.2 to align with the rest of the
  workflow and pull in pnpm's patched bundled brace-expansion (5.0.5
  vs 5.0.4). Fixes 1M.

- Add `uuid@<14.0.0` → `>=14.0.0` to pnpm.overrides
  (GHSA-w5hq-g745-h8pq). Fixes 1M.

- Drop `curl` from the runtime apk add list and switch HEALTHCHECK to
  wget (busybox built-in). curl was only invoked by the healthcheck and
  by dev/CI scripts that don't run in the container. Removes the curl
  CLI binary; libcurl remains as a git transitive dep, so the
  `apk/alpine/curl` advisories scout reports against libcurl persist
  but aren't reachable from any code we ship. As a side-effect this
  also clears nghttp2 (CVE-2026-27135) which was a curl-CLI dep.

- Switch HEALTHCHECK URL from `localhost` to `127.0.0.1` — alpine/musl
  resolves localhost to ::1 first and Etherpad only binds IPv4.

Verified locally: docker build → docker run → healthy → docker scout
cves shows 12 CVEs / 3 packages.

* fix(docker): refresh corepack before preparing pnpm (Qodo)

Node 22's bundled corepack ships a stale signing-key list and can reject
newer pnpm releases (nodejs/corepack#612), which would fail the image
build at `corepack prepare`. Mirror the snap/snapcraft.yaml workaround:
`npm install -g corepack@latest` before activating pnpm, in both
adminbuild and build stages. npm is still removed afterwards.

* docs(changelog): note docker image dropping curl/npm/npx (Qodo)

Address Qodo's "backwards-incompatible change without mitigation" rule
violations by documenting the removal in the 2.7.3 breaking-changes
section. Operators who exec into the container can apk add curl on
demand or use the busybox wget / pnpm already present.

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

* chore: pnpm

---------

Co-authored-by: SamTV12345 <40429738+samtv12345@users.noreply.github.com>
This commit is contained in:
John McLear 2026-05-07 04:00:13 +08:00 committed by GitHub
parent fb09b11ff5
commit 958590d1c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 671 additions and 597 deletions

View file

@ -43,7 +43,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -100,7 +99,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -169,7 +167,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -221,7 +218,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6

View file

@ -54,12 +54,10 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
# Pin Node so the build does not silently fall back to whatever the
# runner image ships with. oxc-minify (a vitepress peer when
# rolldown-vite is in use) requires Node ^20.19.0 || >=22.12.0; the
# repo declares engines.node >=22.12.0 to match.
# runner image ships with. vite 8 requires Node ^20.19.0 || >=22.12.0;
# the repo declares engines.node >=22.12.0 to match.
- name: Use Node.js
uses: actions/setup-node@v6
with:

View file

@ -52,8 +52,10 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
# Repo is checked out into ./etherpad, so the action can't find
# packageManager in a root package.json.
package_json_file: etherpad/package.json
- name: Use Node.js
uses: actions/setup-node@v6
with:

View file

@ -38,7 +38,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6

View file

@ -38,7 +38,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -111,7 +110,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -188,7 +186,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -290,7 +287,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6

View file

@ -38,8 +38,12 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
- name: Install all dependencies and symlink for ep_etherpad-lite
run: pnpm install --frozen-lockfile
- name: Build etherpad

View file

@ -35,7 +35,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -74,7 +73,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
@ -138,7 +136,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6

View file

@ -35,8 +35,12 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
- name: Install all dependencies and symlink for ep_etherpad-lite
run: pnpm install --frozen-lockfile
- name: Perform type check

View file

@ -38,8 +38,12 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
-
name: docker network

View file

@ -57,8 +57,16 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
# Repo is checked out into ./etherpad, so the action can't find
# packageManager in a root package.json.
package_json_file: etherpad/package.json
- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: 22
cache: pnpm
cache-dependency-path: etherpad/pnpm-lock.yaml
- name: Install dependencies ether.github.com
run: pnpm install --frozen-lockfile
working-directory: ether.github.com

View file

@ -33,7 +33,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile

View file

@ -21,7 +21,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js

View file

@ -45,7 +45,6 @@ jobs:
- uses: pnpm/action-setup@v6
name: Install pnpm
with:
version: 10.33.2
run_install: false
- name: Use Node.js
uses: actions/setup-node@v6

View file

@ -6,8 +6,8 @@ Welcome to the Etherpad project. This guide provides essential context and instr
Etherpad is a real-time collaborative editor designed to be lightweight, scalable, and highly extensible via plugins.
## Technical Stack
- **Runtime:** Node.js >= 20.0.0
- **Package Manager:** pnpm (>= 8.3.0)
- **Runtime:** Node.js >= 22.12.0
- **Package Manager:** pnpm (>= 11.0.0)
- **Languages:** TypeScript (primary for new code), JavaScript (legacy), CSS, HTML
- **Backend:** Express.js 5, Socket.io 4
- **Frontend:** Legacy core (`src/static`), Modern React UI (`ui/`), Admin UI (`admin/`)

View file

@ -3,6 +3,7 @@
### Breaking changes
- **Minimum required Node.js version is now 22.12.** Node.js 20 is reaching end-of-life (see https://nodejs.org/en/about/previous-releases) and the docs build's `oxc-minify` peer requires `^20.19.0 || >=22.12.0`. The CI matrix now targets Node 22, 24, and 25. Upgrading should be straightforward — install a current Node.js release before updating Etherpad.
- **The official Docker image no longer ships `curl`, `npm`, or `npx`.** These were dropped to remove transitive CVEs (curl/libcurl SMB advisories, npm's bundled picomatch 4.0.3 and brace-expansion 2.0.2). The container's healthcheck now uses `wget` (busybox built-in, always present), and Etherpad provisions `pnpm` via `corepack` for all runtime package operations. If you exec into the container and rely on `curl` or `npm` for ad-hoc tasks, install them on demand with `apk add curl` or use the busybox `wget` / `pnpm` already present.
### Notable enhancements

View file

@ -7,10 +7,17 @@
# docker build --build-arg BUILD_ENV=copy .
ARG BUILD_ENV=git
ARG PnpmVersion=10.28.2
ARG PnpmVersion=11.0.6
FROM node:22-alpine AS adminbuild
RUN npm install -g pnpm@${PnpmVersion}
# Use corepack to provision pnpm and drop the bundled npm — its older
# transitives (picomatch, brace-expansion) carry CVEs we don't otherwise
# need. Refresh corepack first: the version bundled with Node 22 ships a
# stale signing-key list and rejects newer pnpm releases
# (nodejs/corepack#612). Mirrors the workaround in snap/snapcraft.yaml.
RUN npm install -g corepack@latest && \
corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
WORKDIR /opt/etherpad-lite
COPY . .
RUN pnpm install
@ -96,11 +103,12 @@ RUN mkdir -p "${EP_DIR}" && chown etherpad:etherpad "${EP_DIR}"
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN \
mkdir -p /usr/share/man/man1 && \
npm install pnpm@${PnpmVersion} -g && \
npm install -g corepack@latest && \
corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx && \
apk update && apk upgrade && \
apk add --no-cache \
ca-certificates \
curl \
git \
${INSTALL_SOFFICE:+libreoffice openjdk8-jre libreoffice-common} && \
rm -rf /var/cache/apk/*
@ -165,7 +173,10 @@ ENV ETHERPAD_PRODUCTION=true
# The full pnpm-workspace.yaml references admin, doc, ui which are not
# needed at runtime. Overwrite it with a production-only version so
# pnpm install doesn't warn about missing workspace directories.
RUN printf 'packages:\n - src\n - bin\n' > pnpm-workspace.yaml
# Preserve the build-script policy from the source workspace file so
# pnpm 11 doesn't error out with ERR_PNPM_IGNORED_BUILDS for transitive
# postinstalls (e.g. @scarf/scarf via swagger-ui-dist).
RUN printf 'packages:\n - src\n - bin\nonlyBuiltDependencies:\n - esbuild\nignoredBuiltDependencies:\n - "@scarf/scarf"\nstrictDepBuilds: false\n' > pnpm-workspace.yaml
COPY --chown=etherpad:etherpad ./src ./src
COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/templates/admin ./src/templates/admin
@ -191,7 +202,7 @@ COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json
USER etherpad
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl --silent http://localhost:9001/health | grep -E "pass|ok|up" > /dev/null || exit 1
CMD wget -qO- http://127.0.0.1:9001/health | grep -E "pass|ok|up" > /dev/null || exit 1
EXPOSE 9001
CMD ["pnpm", "run", "prod"]

View file

@ -35,11 +35,8 @@
"react-router-dom": "^7.15.0",
"socket.io-client": "^4.8.3",
"typescript": "^6.0.3",
"vite": "npm:rolldown-vite@7.2.10",
"vite": "^8.0.10",
"vite-plugin-babel": "^1.6.0",
"zustand": "^5.0.13"
},
"overrides": {
"vite": "npm:rolldown-vite@7.2.10"
}
}

View file

@ -10,8 +10,5 @@
},
"peerDependencies": {
"search-insights": "^2.17.3"
},
"overrides": {
"vite": "npm:rolldown-vite@7.2.10"
}
}

View file

@ -42,8 +42,9 @@
"ui": "link:ui"
},
"engines": {
"node": ">=22.12.0"
"node": ">=22.13.0"
},
"packageManager": "pnpm@11.0.6",
"repository": {
"type": "git",
"url": "https://github.com/ether/etherpad.git"
@ -57,24 +58,6 @@
],
"ignoredBuiltDependencies": [
"@scarf/scarf"
],
"overrides": {
"basic-ftp": ">=5.3.0",
"brace-expansion@>=2.0.0 <2.0.3": ">=2.0.3",
"diff@>=6.0.0 <8.0.3": ">=8.0.3",
"flatted": ">=3.4.2",
"follow-redirects": ">=1.16.0",
"glob@>=10.2.0 <10.5.0": ">=10.5.0",
"js-yaml@>=4.0.0 <4.1.1": ">=4.1.1",
"lodash": ">=4.18.0",
"minimatch@>=9.0.0 <9.0.7": ">=9.0.7",
"path-to-regexp@>=8.0.0 <8.4.0": ">=8.4.0",
"picomatch@>=4.0.0 <4.0.4": ">=4.0.4",
"qs@>=6.7.0 <6.14.2": ">=6.14.2",
"serialize-javascript": ">=7.0.5",
"socket.io-parser@>=4.0.0 <4.2.6": ">=4.2.6",
"tar@<7.5.11": ">=7.5.11",
"vite@>=7.0.0 <7.3.2": ">=7.3.2"
}
]
}
}

1111
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -4,14 +4,37 @@ packages:
- bin
- doc
- ui
onlyBuiltDependencies:
- esbuild
allowBuilds:
'@scarf/scarf': set this to true or false
esbuild: set this to true or false
# Explicitly ignore build scripts we don't want to run. Listing them here
# stops pnpm from failing with ERR_PNPM_IGNORED_BUILDS when they're
# encountered as transitive deps (e.g. scarf pulled in via swagger-ui-dist).
ignoredBuiltDependencies:
- '@scarf/scarf'
onlyBuiltDependencies:
- esbuild
# Belt-and-suspenders: even if a fresh transitive dep slips through with a
# postinstall script, downgrade to a warning so CI doesn't break for
# downstream plugin repos that pull etherpad-lite as their core install.
strictDepBuilds: false
# As of pnpm 11, overrides must live here (root package.json's pnpm.overrides
# is no longer read). Force-bump transitive deps with known CVEs.
overrides:
basic-ftp: '>=5.3.0'
brace-expansion@>=2.0.0 <2.0.3: '>=2.0.3'
diff@>=6.0.0 <8.0.3: '>=8.0.3'
flatted: '>=3.4.2'
follow-redirects: '>=1.16.0'
glob@>=10.2.0 <10.5.0: '>=10.5.0'
js-yaml@>=4.0.0 <4.1.1: '>=4.1.1'
lodash: '>=4.18.0'
minimatch@>=9.0.0 <9.0.7: '>=9.0.7'
path-to-regexp@>=8.0.0 <8.4.0: '>=8.4.0'
picomatch@>=4.0.0 <4.0.4: '>=4.0.4'
qs@>=6.7.0 <6.14.2: '>=6.14.2'
serialize-javascript@<7.0.5: '>=7.0.5'
socket.io-parser@>=4.0.0 <4.2.6: '>=4.2.6'
tar@<7.5.11: '>=7.5.11'
uuid@<14.0.0: '>=14.0.0'
vite@>=7.0.0 <7.3.2: '>=7.3.2'

View file

@ -91,8 +91,9 @@ parts:
override-build: |
set -eu
# -- 1. Install Node.js 22 from the official tarball.
NODE_VERSION=22.12.0
# -- 1. Install Node.js 22 from the official tarball. Must be >=22.13
# because pnpm 11 hard-rejects older 22.x releases.
NODE_VERSION=22.22.2
ARCH="$(dpkg --print-architecture)"
case "${ARCH}" in
amd64) NODE_ARCH=x64 ;;
@ -114,7 +115,7 @@ parts:
"${CRAFT_PART_INSTALL}/opt/node/bin/npm" install \
--prefix "${CRAFT_PART_INSTALL}/opt/node" -g corepack@latest
corepack enable --install-directory "${CRAFT_PART_INSTALL}/opt/node/bin"
corepack prepare pnpm@10.33.0 --activate
corepack prepare pnpm@11.0.6 --activate
# -- 3. Copy source into install dir and build.
APP_DIR="${CRAFT_PART_INSTALL}/opt/etherpad"

View file

@ -133,9 +133,9 @@
"vitest": "^4.1.5"
},
"engines": {
"node": ">=22.0.0",
"node": ">=22.13.0",
"npm": ">=6.14.0",
"pnpm": ">=8.3.0"
"pnpm": ">=11.0.0"
},
"repository": {
"type": "git",

View file

@ -12,9 +12,6 @@
"devDependencies": {
"ep_etherpad-lite": "workspace:../src",
"typescript": "^6.0.3",
"vite": "npm:rolldown-vite@7.2.10"
},
"overrides": {
"vite": "npm:rolldown-vite@7.2.10"
"vite": "^8.0.10"
}
}

View file

@ -6,7 +6,7 @@ export default defineConfig({
base: '/views/',
build: {
outDir: resolve(__dirname, '../src/static/oidc'),
rolldownOptions: {
rollupOptions: {
input: {
main: resolve(__dirname, 'consent.html'),
nested: resolve(__dirname, 'login.html'),