fix(deps): clear the critical websocket-driver advisory and unbreak npm ci#102
fix(deps): clear the critical websocket-driver advisory and unbreak npm ci#102Prekzursil wants to merge 1 commit into
Conversation
…pm ci
`npm ci` was broken on main itself, which blocked every dependency PR from
being verifiable:
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and
npm error package-lock.json or npm-shrinkwrap.json are in sync.
npm error Invalid: lock file's ws@7.5.11 does not satisfy ws@7.5.13
Root cause: the `ws: ^7.5.11` override forced the whole tree onto the ws 7.x
line, but the lock still carried a nested `webdriver/node_modules/ws@8.21.0`
that VIOLATES that override. ws was the only override in the tree with a
violating node, which is why it was the only package npm named. The broken edge
made arborist re-resolve the ws family, and `^7.5.11` now resolves to 7.5.13
(7.5.12/7.5.13 published after the lock was written), so the freshly-built
ideal tree disagreed with the pinned lock.
The `ws` override no longer serves a security purpose (no ws version in the tree
is flagged) and it was downgrading consumers that ask for ws 8.x
(@storybook/core, webpack-dev-server), so it is removed rather than re-pinned.
The lock is regenerated, not hand-edited.
Dependabot alerts closed:
* websocket-driver 0.7.4 -> 0.7.5 GHSA-xv26-6w52-cph6 (CRITICAL, CVSS 9.2)
* websocket-driver 0.7.4 -> 0.7.5 GHSA-mp7j-qc5w-4988 (medium)
* fast-xml-parser 5.9.3 -> 5.10.1 GHSA-8r6m-32jq-jx6q (high)
The `quality` gate additionally requires osv-scanner clean-zero, so the rest of
the flagged tree is brought up too: Django 5.2.15 -> 5.2.16, and bounded-floor
overrides (never exact pins) for body-parser, fast-uri, find-my-way, sharp,
shell-quote, svgo, plus raised floors for postcss, js-yaml and
webpack-dev-server. brace-expansion resolves to 1.1.16 / 2.1.2 naturally once
the stale lock is regenerated.
react-router-dom 6.30.4 is replaced by react-router ^7.18.0. GHSA-jjmj-jmhj-qwj2
has NO fix anywhere in the react-router-dom 6.x line, and v7 deprecates the
react-router-dom shim in favour of importing from react-router directly, so the
37 module specifiers under src/ are rewritten. The shim also cannot be used
here: its CJS entry requires the `react-router/dom` subpath export, which CRA
5's jest 27 resolver cannot resolve. A branch-free TextEncoder/TextDecoder
polyfill is added to setupTests.ts because react-router v7 constructs a
`new TextEncoder()` at module scope and jest 27's jsdom does not expose it.
Two new reasoned, dated IgnoredVulns entries are recorded in osv-scanner.toml
per that file's existing policy. Both are genuinely unfixable here and are
argued for reachability inline. They are the two judgement calls in this change
and are the right place to push back:
* GHSA-qwww-vcr4-c8h2 (react-router) - the advisory states it only affects the
unstable RSC APIs; this is a CRA client-side SPA with no RSC/SSR/data-router.
The fix, react-router 8.3.0, peer-requires React >= 19.2.7 and this app is on
React 18.3.1.
* GHSA-mh99-v99m-4gvg (brace-expansion) - no patched release exists below
5.0.8 in any line, and forcing >=5.0.8 breaks the build outright
("[eslint] expand is not a function", measured).
Local verification (frontend/webcoder_ui): npm ci exit 0, tsc --noEmit exit 0,
react-scripts build "Compiled successfully", 25/25 test suites and 236/236 tests
pass at 100% statements/branches/functions/lines, oxlint@1.69.0
--deny-warnings exit 0, and osv-scanner 2.3.8 (the version CI pins) reports
"No issues found" exit 0 on the frontend lockfile, down from 25 vulnerabilities.
CI is green — but the merge is blocked by a stale required-check name (owner action needed)All 9 checks pass on
Why it is blocked (not caused by this PR)Branch protection on That context no longer exists. This repo has been switched to GitHub's default CodeQL setup, which disables the advanced workflow-based scan. On this PR head the CodeQL run is Evidence that this is pre-existing drift, not this branch:
Because The fix (one line, owner-only)Update branch protection's required contexts from I have deliberately not touched branch protection and have not merged with One flake worth knowing about
preceded by Zero vulnerabilities, exit 127. For osv-scanner, |
Why
Two separate things were wrong, and the first was hiding the second.
1.
npm ciwas broken onmainitself, so no dependency PR in this repo could be verified or merged:Reproduced on a clean clone of
main(477b7ae).What was out of sync: the
ws: "^7.5.11"override forced the whole tree onto the ws 7.x line, but the lock still carried a nestedwebdriver/node_modules/ws@8.21.0, which violates that override. A scan of all 12 overrides against the lock foundwswas the only one with a violating node — which is exactly why npm named onlyws. That broken edge makes arborist re-resolve the ws family, and^7.5.11now resolves to7.5.13(7.5.12/7.5.13 were published after the lock was written), so the freshly-built ideal tree disagreed with the pinned lock.The
wsoverride is removed rather than re-pinned: no ws version in the tree is flagged by any advisory any more, and the override was actively downgrading consumers that ask for ws 8.x (@storybook/corewants^8.2.3,webpack-dev-serverwants^8.18.0). The lock was regenerated, not hand-edited.2. The required
qualitygate needs osv-scanner clean-zero, and the tree carried 25 known vulnerabilities. Closing only the 3 Dependabot alerts would still have left the gate red, so the whole flagged set is brought up.Dependabot alerts closed
Each verified against the advisory's own range, not a summary. All floors are bounded (
>=X <NextMajor) — no exact pins, so Dependabot can still see and propose newer patches.Also brought to clean-zero for the gate
Django 5.2.15 -> 5.2.16; new bounded-floor overrides forbody-parser,fast-uri,find-my-way,sharp,shell-quote,svgo; raised floors forpostcss,js-yaml,webpack-dev-server.brace-expansionreaches its patched 1.1.16 / 2.1.2 naturally once the stale lock is regenerated — no override needed.react-router-dom -> react-router (the one behavioural change)
GHSA-jjmj-jmhj-qwj2has no fix anywhere in the react-router-dom 6.x line (introduced 6.30.2, last_affected 6.30.4, nofixedevent). v7 also deprecates thereact-router-domshim in favour of importing fromreact-routerdirectly, so the dependency is replaced and the 37 module specifiers undersrc/are rewritten.The shim is additionally unusable here: its CJS entry
requires thereact-router/domsubpath export, which CRA 5's jest 27 resolver cannot resolve (Cannot find module 'react-router/dom'— 18 suites failed to load when it was tried).react-router's main entry exports all 10 APIs this app uses (BrowserRouter,MemoryRouter,Routes,Route,Link,NavLink,Navigate,useNavigate,useParams,useLocation) — verified at runtime.setupTests.tsgains a branch-freeTextEncoder/TextDecoderpolyfill: react-router v7 constructs anew TextEncoder()at module scope and jest 27's jsdom does not expose it. Branch-free deliberately, because this project enforces a 100% branch coverage threshold and anif (!global.TextEncoder)guard would add an uncovered branch.Recorded in
osv-scanner.tomlper that file's existing policy (reasoned + dated + greppable), with the reachability argument inline. This is the part of the PR to push back on.GHSA-qwww-vcr4-c8h2(react-router 7.18.1) — the advisory text itself says "This only affects your application if you are using the unstable RSC APIs". This is a CRA client-side SPA;src/has no match forrsc/matchRSCServerRequest/createStaticHandler/StaticRouter/renderToString/renderToPipeableStream/unstable_/createBrowserRouter/RouterProvider, and no routeloader:/action:. Genuinely unfixable on React 18: the fix is react-router 8.3.0, whose peers requirereact >= 19.2.7; this app is on React 18.3.1, andreact-router-domhas no 8.x at all (E404). The union of the four open react-router advisories covers>=6.0.0 <8.3.0, so on React 18 no clean version exists — 7.18.x is the minimum-vulnerability choice, and it clears the other three.GHSA-mh99-v99m-4gvg(brace-expansion) — single affected rangeintroduced 0, fixed 5.0.8, so no patched release exists in any line below 5.0.8. Forcing>=5.0.8 <6was attempted and broke the build outright:[eslint] expand is not a function, because 5.0.8 restructured to an exports map with no callable default while minimatch 3.x doesrequire("brace-expansion")(). Reached only by build/test-time glob tooling on repo-authored patterns; not in the shipped bundle.Both carry a re-review trigger (React 19 migration; a 1.x/2.x backport or moving off minimatch 3.x).
Local verification
Run in
frontend/webcoder_uiunless noted.osv-scanneris 2.3.8, the version CI pins.npm ciEUSAGEonmain)tsc --noEmitreact-scripts buildCompiled successfully.react-scripts test --coverage --watchAll=false --cioxlint@1.69.0 --deny-warningsbiome@2.5.0 ci(formatter)git archive, since the CRLF worktree gives a false 73-file failure on Windows;main's blob was used as the control and also passesosv-scanner --lockfile=frontend/webcoder_ui/package-lock.jsonNo issues found, exit 0 — down from 25 vulnerabilities (1 critical, 14 high)osv-scanner's PyPI transitive-dependency resolution is currently failing upstream:This is present on
maintoo (it appears in the 2026-07-24 runs of #98 and #101). It matters because of osv-scanner's exit codes: 1 = vulnerabilities found, but 127 = HasErrored. While vulnerabilities existed the scan exited 1, so the error was masked. Now that the tree is clean, a full recursive scan locally reportsTotal 0 packages affected by 0 known vulnerabilitiesand still exits 127 purely because of that outage — and the gate's shell fails anything that is not 0 or 128.So if
gate-depsgoes red on this PR, check the exit code and grep forservice unavailablebefore reading it as a security finding. A 127 there is an infrastructure flake and should be re-run, not "fixed" by changing a dependency. Isolating the two sources locally: frontend lockfile alone -> exit 0;requirements.txtalone -> exit 127 with only that resolver error. There is no repo-side switch (--no-resolvelives on the scanner invocation in the reusable workflow, not inosv-scanner.toml).Relationship to the open Dependabot PRs
This supersedes the content of #98 (websocket-driver 0.7.5) and #101 (fast-xml-parser 5.10.1) — both of which fail the required
qualitygate on their own, because each fixes one package while the gate demands clean-zero. I have deliberately not touched, closed or rebased #98, #99, #100 or #101 — that call is left to the owner.