Repository navigation
fix(deps): clear 8 advisories, and pin the Node that writes the lockfile - #659
Merged
Merged
Conversation
…udit` on dev `ci-frontend` is the only red workflow on dev, and has been since 7193fbc. It fails at `npm audit --audit-level=high` — not on a code change, but on advisories published against versions already pinned. The gate ignores the moderates, so these 8 are what matter: critical astro <=7.2.7 RCE via AVIF image optimization high sharp <0.35.4 libheif GHSA-g89c-p67h-r497 / -2jg2-4ch7-h545 high svgo 4.0.0-4.0.2 removeScripts sanitiser bypasses (x2) high smol-toml <=1.7.0 DoS via malformed TOML high js-yaml 4.0.0-4.3.1 maxTotalMergeKeys does not bound CPU high browserslist <=4.28.6 unbounded cache growth -> OOM high fast-uri 3.0.0-3.1.5 host confusion via skipped IDN canonicalisation high @xmldom/xmldom <=0.8.14 XML fragment injection via EntityReference Every move is a patch/minor INSIDE the existing ranges: astro 7.2.0 -> 7.3.3 (satisfies ^7.2.0), sharp 0.35.3 -> 0.35.4, svgo 4.0.2 -> 4.1.0, smol-toml 1.7.0 -> 1.8.0, js-yaml 4.3.1 -> 4.3.2, browserslist 4.28.6 -> 4.29.0, fast-uri 3.1.5 -> 3.1.8, xmldom 0.8.13 -> 0.8.15. No manifest changes and no new direct dependency; only package-lock.json moves and every package.json is byte-identical. It is all the apps/website (Astro) tree — nothing in apps/desktop or packages/* moves. BUILD IT ON THE NPM CI ACTUALLY RUNS. The workflow pins node 22, which brings npm 10.9.8, and that pairing is what the lockfile has to satisfy. Two traps: 1. npm 10.9.8 cannot run `npm audit fix` in this repo at all — it dies on `"playwright": "$playwright"` in the root overrides with `Unable to resolve reference $playwright`. Plain `npm install --package-lock-only` and `npm update` are unaffected, so the bumps are done with those. Worth replacing that `$playwright` reference with its literal version if we want `audit fix` back. 2. Reaching for a newer npm to get around (1) produces a lockfile that reds the NEXT gate. npm 11.9's resolver nests un-overridden copies of @electron/asar@3.4.1, @electron/universal@2.0.3 and ejs@3.1.10 under app-builder-lib — the exact pre-override versions the root `overrides` block exists to eliminate — and strands the @img/sharp-wasm32 subtree that sharp 0.35.4 stops referencing. npm 10.9.8 then reports 3 invalid and 7 extraneous from `npm ls`, which is what `cyclonedx-npm` shells out to, so the SBOM step fails. Measured both ways on this repo: dev lockfile npm 11.9-built lockfile npm 10.9.8 (CI) npm ls exit 0 exit 1 — 7 extraneous, 3 invalid npm 11.9.0 (local) exit 1 — 11 probs exit 1 — 10 probs Under npm 11.9 both look broken, so a local check cannot tell them apart. Under CI's npm only the bad one fails. Verified on node 22.23.2 / npm 10.9.8, the workflow's pinned pair: `npm ci` clean, `npm audit --audit-level=high` passes, `npm ls --json --long --all` exits 0, the SBOM step produces a valid CycloneDX 1.6 document, all six package typechecks at 0 errors, frontend builds, and the website — the only tree that moved — builds on the bumped Astro. The same lockfile is already green across all 14 checks on #658, which carries it so that PR could pass while dev was red. This lands it on dev directly so it stops depending on unrelated feature work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…s one thing
The red `build-and-audit` this branch already repairs was a symptom. The cause
is that nothing here says which Node and npm the repo is built with, so four of
them touch one `package-lock.json`:
developer Mac Node 25 / npm 11.9 WRITES the lockfile
8 CI job steps Node "22" / npm 10.9 JUDGE the lockfile
apps/frontend node:26-alpine INSTALLS from the lockfile
ci-cli (2 jobs) Node "20" one deliberate, one accidental
npm 10 and npm 11 do not agree on what a valid tree is. Measured on this repo:
under npm 10.9.8 the dev lockfile passes `npm ls` and an npm-11.9-edited one
fails with 7 extraneous and 3 invalid; under npm 11.9 BOTH look broken, so a
local check cannot tell a good lockfile from a bad one. That is the whole
failure, and it is why the earlier deps commit concluded — on the Mac's npm —
that a break it had just introduced was pre-existing.
The same drift is already written into this repo as workarounds. `ci-cli`
explains an unquoted glob with "this job runs Node 20 ... the desktop workflow
gets away with the quoted form only because it runs Node 22". `release-cli`
opens with "Node 22, not the 20 the CI workflows use". Each is a note about
which Node happens to be underneath.
So: say it once, enforce it, and point everything at it.
.nvmrc 22.23.2 — the version CI already resolves today
package.json engines the same, so npm can check it
.npmrc engine-strict a refusal, not an advisory warning
8 workflow steps node-version-file: .nvmrc, no version of their own
apps/frontend node:22.23.2-alpine
This is the pattern the kaleidoscope-docs repo already uses for the same
reason. On the wrong Node, npm now stops before writing anything:
npm error code EBADENGINE
npm error notsup Required: {"node":"22.23.2"}
npm error notsup Actual: {"node":"v25.6.1","npm":"11.9.0"}
ONE DELIBERATE EXCEPTION, now stated in the file instead of implied: ci-cli's
`cli` matrix job stays on Node 20, because its job is to prove the published
launcher still runs on the oldest Node `tools/cli` claims to support
(`engines: >=20`). It installs nothing from the root lockfile, and `engine-strict`
gates installs only — verified that `npm run check`, `npm run smoke` and the
pack-manifest check all still pass there on Node 20.
That job's neighbour, `packed-payload`, moves ONTO the pin: it runs `npm ci` at
the repo root, so it was a builder wearing a floor-test's Node. Its glob comment
goes with it, having described a Node 20 quirk it no longer runs into.
`release-cli` keeps its explicit `npm install -g npm@^11.5.1`: trusted
publishing needs OIDC, which npm 10 has not got. That upgrade only ever runs
`npm ci`, which reads the lockfile and never rewrites it, so it cannot
reintroduce the drift.
The lockfile carries the root `engines` too, so it is regenerated in step —
without that, manifest and lockfile disagree quietly and `npm ci` still passes.
Verified on node 22.23.2 / npm 10.9.8: `npm ci` clean, `npm audit
--audit-level=high` passes, `npm ls --json --long --all` exits 0, SBOM builds,
six typechecks at 0 errors, frontend and website build, playwright version check
passes, desktop-runtime tests pass. On Node 20: the cli floor job passes. On
Node 25: npm refuses, which is the point.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
build-and-audit on dev
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ci-frontend / build-and-auditis red on dev atnpm audit --audit-level=high. This clears it — and then fixes the reason it happened.The repair
Eight advisories published against already-pinned versions. Every move is a patch/minor inside the existing ranges, no manifest changes, no new direct dependency:
The cause
Nothing in this repo says which Node and npm it is built with, so four of them touch one
package-lock.json:"22"/ npm 10.9apps/frontendnode:26-alpineci-cli(2 jobs)"20"npm 10 and npm 11 do not agree on what a valid tree is. Measured here:
npm lsexit 0Under npm 11.9 both look broken, so a local check cannot tell a good lockfile from a bad one. That is why an earlier attempt at these same bumps concluded — on the Mac's npm — that a break it had just introduced was pre-existing.
The drift is already written into this repo as workarounds.
ci-cliexplains an unquoted glob with "this job runs Node 20 … the desktop workflow gets away with the quoted form only because it runs Node 22".release-cliopens with "Node 22, not the 20 the CI workflows use". Each is a note about which Node happens to be underneath.The fix — say it once, enforce it, point everything at it
.nvmrc22.23.2— the version CI already resolves todaypackage.jsonengines.npmrcengine-strict=truenode-version-file: ".nvmrc", no version of their ownapps/frontend/Dockerfilenode:22.23.2-alpineSame pattern the
kaleidoscope-docsrepo already uses for the same reason. On the wrong Node, npm now stops before writing anything:One deliberate exception, now stated in the file instead of implied:
ci-cli'sclimatrix job stays on Node 20, because its job is to prove the published launcher still runs on the oldest Nodetools/cliclaims to support (engines: >=20). It installs nothing from the root lockfile, andengine-strictgates installs only — verifiednpm run check,npm run smokeand the pack-manifest check all still pass there on Node 20.Its neighbour
packed-payloadmoves onto the pin: it runsnpm ciat the repo root, so it was a builder wearing a floor-test's Node.release-clikeeps its explicitnpm install -g npm@^11.5.1— trusted publishing needs OIDC, which npm 10 has not got. That upgrade only ever runsnpm ci, which reads the lockfile and never rewrites it, so it cannot reintroduce the drift.Verification
On node 22.23.2 / npm 10.9.8, the pinned pair:
npm ciclean ·npm audit --audit-level=highpasses ← the step dev fails onnpm ls --json --long --allexits 0 · SBOM builds (valid CycloneDX 1.6)On Node 20: the cli floor job passes. On Node 25: npm refuses — which is the point.
The lockfile carries the root
enginestoo, so it is regenerated in step; without that, manifest and lockfile disagree quietly andnpm cistill passes.The advisory half of this is already green across all 14 checks on #658, which carries it so that PR could pass while dev was red.
🤖 Generated with Claude Code