* Roll Node.js floor back to >= 24 (Active LTS) Closes #7779. #7779 originally proposed bumping past the Node 25 stop-gap to Node 26. After re-checking the release schedule, the cleaner LTS target is actually Node 24: - Node 24 (Krypton) is currently in Active LTS, supported until ~May 2028. - Node 25 hit end-of-life on April 10 2026 — the floor merged in #7752 / #7749 / #7754 a day ago ships an already-EOL major. - Node 26 was released May 5 2026 and does not enter Active LTS until October 2026. So this PR reverts the Node 25 ratchet from those three PRs and lands on Node 24 — Etherpad's runtime floor stays on a supported LTS for the next ~2 years. Runtime / infra - `package.json` + `src/package.json`: `engines.node` `>=25.0.0` -> `>=24.0.0` - `bin/functions.sh`, `bin/installer.sh`, `bin/installer.ps1`: `REQUIRED_NODE_MAJOR` 25 -> 24 - `Dockerfile`: `node:25-alpine` -> `node:24-alpine` (both stages). Corepack-via-npm workaround is intentionally kept: it works on Node 24 (which still ships corepack) and on Node 25+ (which doesn't), so the same recipe survives the next LTS bump without churn. Comments reworded accordingly. - `snap/snapcraft.yaml`: pinned `NODE_VERSION` 25.9.0 -> 24.15.0; design notes + corepack comment adjusted - `packaging/nfpm.yaml`: `nodejs (>= 25)` -> `nodejs (>= 24)` in top-level depends + deb/rpm overrides - `packaging/bin/etherpad`: comment matches the new pin - `packaging/README.md`: build prereqs + apt install snippet point at `node_24.x`; the long-stale "engines.node floor is 20" line is fixed while we're here - `.github/workflows/*.yml`: setup-node `node-version` 25 -> 24 across every workflow; backend / frontend-admin / upgrade matrices `[25]` -> `[24]` - `.github/workflows/deb-package.yml`: `NODE_MAJOR=25` + `node_25.x` smoke-test installer -> 24 - `bin/plugins/lib/npmpublish.yml`: 25 -> 24 (template propagates to the ~80 ether/* plugins via update-plugins workflow) Docs - `README.md`: install one-liner + Requirements -> Node.js >= 24 - `doc/npm-trusted-publishing.md`: runner requirement -> Node 24 - `doc/plugins.md` / `doc/plugins.adoc`: plugin metadata example `engines.node` -> `">=24.0.0"` @types/node is left at ^25.8.0 — newer type definitions cover Node 24 runtime fine and avoid an unnecessary lockfile churn. Companion homepage one-liner change to follow on ether/ether.github.com. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(plugins): example engines.node = ">=22.0.0", not core's floor Plugin code is overwhelmingly ace-hook glue and rarely uses Node-version- specific APIs, so plugin engines.node should reflect the plugin's own requirements, not track core. Showing core's 24-floor in the example encouraged plugin authors to blindly copy a tighter pin than necessary and locked plugins out of being installable on older Etherpad/Node deployments. Use the most-recent Node LTS that has actually reached EOL (20 -> EOL April 2026) as the example floor, i.e. >=22. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.4 KiB
npm Trusted Publishing (OIDC)
Etherpad and every ether/ep_* plugin publish to npm using
npm Trusted Publishing over OpenID Connect. This eliminates the need
to store, rotate, or accidentally leak long-lived NPM_TOKEN secrets — each
publish is authenticated against the GitHub Actions runner with a short-lived
OIDC token instead.
How it works
- The publish workflow declares
permissions: id-token: write. - GitHub Actions issues a signed OIDC token to the runner.
- The npm CLI (>= 11.5.1) trades that OIDC token for a short-lived publish credential against npmjs.com.
- npmjs.com checks the OIDC claims (org, repo, workflow file, branch / environment) against the package's configured trusted publisher and, if they match, accepts the publish. Provenance attestations are recorded automatically.
No NPM_TOKEN secret is needed in any plugin or in core.
One-time setup per package
Trusted publishing has to be enabled once per package. Use the bundled
script to do every package in one go via the npm trust CLI (npm >= 11.5.1):
# 1. Make sure npm CLI is recent enough
npm install -g npm@latest
# 2. Log in to npmjs.com as a maintainer
npm login
# 3. Bulk-configure every ether/ep_* plugin + ep_etherpad
bin/setup-trusted-publishers.sh
# Or preview without changing anything
bin/setup-trusted-publishers.sh --dry-run
# Or target a specific subset
bin/setup-trusted-publishers.sh --packages ep_align,ep_webrtc
# Or ignore packages that are already configured (the registry only allows
# one trust relationship per package today)
bin/setup-trusted-publishers.sh --skip-existing
# Supply a 2FA OTP up front (required if your npm account has 2FA enabled —
# it should). The same OTP is reused for every package call inside the same
# minute, so for large batches you may need to chunk via --packages.
bin/setup-trusted-publishers.sh --otp 123456
2FA / OTP note.
npm trust githubrequires an OTP whenever the account has 2FA enabled. Without--otp, npm will prompt interactively per package, which is unworkable in bulk. Pass--otp <code>once and the script will forward it to everynpm trust githubcall. TOTP codes typically expire every 30 seconds, so for >30s runs split the work with--packages ep_a,ep_b,...and re-run with a fresh code.
The script discovers all non-archived ether/ep_* repos via gh repo list
and runs npm trust github <pkg> --repository <org>/<repo> --file <workflow> --yes for each one. ep_etherpad is mapped to the etherpad-lite repo and
the releaseEtherpad.yml workflow; everything else is mapped to its
same-named repo and test-and-release.yml.
If you'd rather click through the npmjs.com UI for a single package: open
https://www.npmjs.com/package/<name>/access → Trusted Publisher →
Add trusted publisher → Publisher: GitHub Actions, Organization: ether,
Repository: as above, Workflow filename: as above, Environment: blank.
Once added, the next push to main/master will publish via OIDC with no
token at all.
Migrating an existing package
If a package previously had an NPM_TOKEN secret in CI:
- Add the trusted publisher on npmjs.com (steps above).
- Bump the workflow to the OIDC version — done in
bin/plugins/lib/npmpublish.yml(which is propagated to every plugin by theupdate-pluginsworkflow). - Remove the now-unused
NPM_TOKENsecret from the GitHub repo settings.
Requirements
-
Node.js: >= 24 on the runner.
setup-node@v6 with version: 24resolves to the latest 24.x. The project'sengines.noderequires>=24.0.0. -
npm CLI: >= 11.5.1. The publish workflow runs
npm install -g npm@latestbefore publishing so the bundled npm version doesn't matter. -
Runner: must be a GitHub-hosted (cloud) runner. Self-hosted runners are not yet supported by npm trusted publishing.
-
package.json: must declare arepositoryfield pointing at the GitHub repo so npm can verify the OIDC claim. Example:{ "repository": { "type": "git", "url": "https://github.com/ether/ep_align.git" } }
Why call npm publish directly?
The publish workflows run npm publish --provenance --access public rather
than pnpm publish or gnpm publish. Both wrappers shell out to whichever
npm is on PATH, but they obscure version requirements: trusted publishing
requires npm >= 11.5.1, and going through the wrapper makes it easy to end up
with the wrong CLI version. Invoking npm directly removes that ambiguity.
pnpm is still used for everything else (install, build, version bump) — only
the final publish step calls npm directly.
Troubleshooting
npm error 404 Not Found - PUT https://registry.npmjs.org/<pkg>
The trusted publisher hasn't been configured on npmjs.com for that package, or the repository / workflow filename in the trusted publisher config doesn't match the running workflow. Double-check the workflow filename — it must be the basename of the workflow YAML, not the job name.
npm error code E_OIDC_NO_TOKEN
The workflow is missing permissions: id-token: write. Add it to the job
(or to the top-level permissions: block).
npm error need: 11.5.1
The runner is using an older bundled npm. The workflow runs
npm install -g npm@latest to fix this — make sure that step ran before the
publish step.