Skip to content

Resolve all 30 Dependabot alerts (client): webpack 5 + jest 30 modernization#36

Merged
rubenhensen merged 9 commits into
masterfrom
chore/fix-dependabot-client-vulns
Jun 18, 2026
Merged

Resolve all 30 Dependabot alerts (client): webpack 5 + jest 30 modernization#36
rubenhensen merged 9 commits into
masterfrom
chore/fix-dependabot-client-vulns

Conversation

@rubenhensen

Copy link
Copy Markdown

What

Resolves all 30 open Dependabot alerts in the client (16 high, 10 moderate, 4 low). Every alert was a transitive npm dependency. Where possible these are fixed at the root (dependency removed/upgraded) rather than only pinned via overrides.

Package Was Now How
webpack-dev-server 3.11 5.2.5 direct bump (clears its 4 source-code-theft alerts)
node-forge 0.10 gone wds3 subtree removed
webpack-dev-middleware 3.7 7.4 via wds5
ip 1.1.9 gone wds5 doesn't use it (no patched version exists)
elliptic 6.6.1 gone webpack 5 drops auto node-polyfills (no patched version exists)
tar 6.2 gone copy-webpack-plugin 12 dropped cacache
braces 2.3.2 3.0.3 jest 30 dropped sanemicromatch@3
postcss 7.0.39 8.5.x removed unused stylelint + css-loader 6
serialize-javascript 4/5 7.0.5 override
uuid 3/8 11.1.1 override
@tootallnate/once 1.1.2 gone/2.x override + jest 30

Why a migration was needed

elliptic and ip have no patched version (even latest is flagged), so the only fix is removing them from the tree — which requires webpack 5 (drops the node-polyfill crypto-browserifyelliptic chain) and webpack-dev-server 5 (drops ip). The webpack-dev-server alerts live in its own code and are only fixed in v5, which requires webpack 5. braces@2.3.2 is dragged in by jest 26's sane, so jest also had to move. The user approved major bumps for this.

Key changes

  • webpack 4 → 5, webpack-dev-server 3 → 5, jest 26 → 30, copy-webpack-plugin 6 → 12, css-loader/style-loader/html-webpack-plugin/babel-loader bumped.
  • Replaced abandoned awesome-typescript-loader with babel-loader + tsconfig-paths-webpack-plugin; removed react-hot-loader, write-file-webpack-plugin, clean-webpack-plugin, and the unused stylelint toolchain.
  • Added resolve.fallback polyfills for browser libs (eventsource, vfile). crypto is intentionally not polyfilled so elliptic stays out of the tree.
  • Pinned ajv@^8 to fix the eslint7/webpack5 ajv-keywords hoisting conflict.
  • jest 30: babel-jest (drops ts-jest), explicit jsdom env, toBeCalledtoHaveBeenCalled, useFakeTimers({ advanceTimers: true }). Also fixed pre-existing stale geocode test mocks (geodata.nationaalgeoregister.nlapi.pdok.nl) and regenerated snapshots.

Verification

npm ci, npm run build, and npm test all pass locally (12 suites / 47 tests green; jest 30 also fixes the jest-worker crashes the suite hit under Node 26). CI builds the client via Dockerfile.prod (npm ci && npm run build).

Out of scope

npm audit still reports 19 moderates, all tracing to a single js-yaml advisory (GHSA-h67p-54hq-rp68) that has no patched version, pulled via eslint@7 and jest's coverage instrumenter. These were not in the Dependabot alert set; clearing them needs an eslint 9 migration — a sensible follow-up.

…modernization

Resolves all 30 open Dependabot alerts (16 high, 10 moderate, 4 low) in the
client. Every alert was a transitive npm dependency; fixed at the root where
possible rather than only pinning overrides.

Root-cause fixes:
- webpack 4 -> 5 and webpack-dev-server 3 -> 5. Removes the wds3 subtree
  (node-forge, webpack-dev-middleware, ip, uuid-via-sockjs) and webpack 4's
  automatic node polyfills (elliptic via crypto-browserify). Clears the four
  wds source-code-theft alerts and the no-fix-available elliptic/ip alerts
  (only removal from the tree helps those).
- copy-webpack-plugin 6 -> 12 (drops cacache, removing vulnerable tar).
- jest 26 -> 30 (drops sane -> micromatch@3 -> braces@2; also fixes the
  jest-worker crashes under Node 26).
- Remove the unused stylelint toolchain (the only source of postcss@7;
  it was not wired into any npm script).

Leaf overrides for deps with no clean parent bump:
- serialize-javascript ^7.0.5, uuid ^11.1.1, @tootallnate/once ^2.0.1,
  node-forge ^1.4.0, postcss ^8.5.10.

Build/config migration:
- Replace abandoned awesome-typescript-loader with babel-loader +
  tsconfig-paths-webpack-plugin.
- webpack-merge smartStrategy -> plain merge; output.clean replaces
  clean-webpack-plugin; devServer.devMiddleware.writeToDisk replaces
  write-file-webpack-plugin; remove react-hot-loader (unused).
- resolve.fallback polyfills (path/util/url/http/https/buffer) for browser
  libs (eventsource via irma-client, vfile via react-markdown). crypto is
  intentionally NOT polyfilled so elliptic stays out of the tree.
- Pin ajv ^8 to fix the eslint7/webpack5 ajv-keywords hoist conflict.
- Relax strictExportPresence (webpack 5's CJS-interop static analysis is
  stricter; the imports resolve correctly at runtime).
- Remove unused styled-components/cssprop import (broke under babel-loader).

Tests (jest 30):
- babel-jest replaces ts-jest; explicit jsdom test environment.
- toBeCalled -> toHaveBeenCalled; useFakeTimers({ advanceTimers: true }) so
  testing-library async queries resolve under modern fake timers.
- Fix stale geocode mocks (geodata.nationaalgeoregister.nl -> api.pdok.nl)
  and regenerate snapshots.

Verified: npm ci, npm run build, and npm test (12 suites, 47 tests) all pass.

The 19 remaining npm-audit moderates all stem from a single js-yaml advisory
(GHSA-h67p-54hq-rp68) with no patched version available, pulled via eslint@7
and jest's coverage instrumenter. Not part of the Dependabot alert set.
The delivery pipeline previously only built and scanned a Docker image,
so runtime JS errors introduced during the webpack 5 migration were never
caught before deployment.

Changes:
- Add `test` CI job that runs `npm test` and `npm run build`, uploading
  the dist as an artifact for the e2e job.
- Add `e2e` CI job that serves the built dist with `serve -s` and runs a
  Playwright smoke test asserting zero JS errors and a visible h1.
- Gate `publish-docker-image` on `needs: [e2e]` so broken builds can't ship.
- Fix `babel.config.js`: add `sourceType: 'unambiguous'` so already-compiled
  CJS packages processed by babel-loader (e.g. @Amsterdam, @privacybydesign)
  receive `require()` polyfills instead of `import` statements, preventing
  webpack 5 from treating them as ES modules where `exports` is undefined.
- Fix `webpack.common.js`: add `ProvidePlugin` for `process/browser.js`
  since webpack 5 no longer shims `process` automatically (needed by
  `proxy-from-env` via axios).
- Scope jest `testRegex` to `src/` so jest ignores the Playwright e2e dir.
…isplay

Production credentials like pbdf.pbdf.passport.firstName resolve to the
key 'firstName' (not 'firstnames'), so the fallback that concatenated
firstnames + surname produced 'undefined undefined' for those users.

Add an intermediate check for firstnames/surname before falling back to
firstName/lastName to cover all three credential sources in the config.
…rors

The /dataselectie/bag/ endpoint now returns 403, causing getGGW() to
throw. Because resultCallback had no error handling around the GGW call,
dispatch() never ran and the result page never appeared after scanning.

- Rewrite getGGW to use the Amsterdam v1 API:
    1. /v1/bag/nummeraanduidingen/?postcode=X  → verblijfsobject href
    2. /v1/bag/verblijfsobjecten/{id}?_expandScope=ligtInBuurt,...
       → wijk naam (buurtcombinatie) + ggwgebied naam/code in one call
- Wrap the getGGW call in Demo2's resultCallback with try/catch so
  dispatch() always fires and the result page shows even if the lookup
  fails (e.g. API is unreachable or postcode has no match).
- Update the axios mock in test/utils.tsx to match the new endpoints.
- actions/checkout v4 → v6
- actions/setup-node v4 → v6
- actions/upload-artifact v4 → v7
- actions/download-artifact v4 → v8
- docker/metadata-action v5 → v6
- docker/setup-buildx-action v3 → v4
- docker/login-action v3 → v4
- docker/build-push-action v5 → v7
- github/codeql-action/upload-sarif v4.36.0 → v4.36.2 (SHA pinned)
- anchore/scan-action already at latest v7.4.0, no change
…i-* packages

Replaces irma-client/core/css/web 0.3.3 with the successor yivi-client/core/css/web 1.0.x
packages. The API is identical (use(), start(), abort()), only the import names changed:
IrmaCore → YiviCore, Web → YiviWeb, Client → YiviClient.

Also mocks @privacybydesign/yivi-css in jest (same as the old irma-css needed) to prevent
jest from trying to parse the raw CSS file as JavaScript.
…exports

The 1.0.0 yivi packages export YiviCore, YiviWeb, and YiviClient as named
exports only. The previous `import Foo from '...'` syntax resolved to
module.default which is undefined, causing the runtime error
"r.default is not a constructor".
Passes minimal: true to YiviCore so yivi-web renders only the bare QR
code (yivi-web-minimal) without its full form chrome. Also updates the
IrmaSessionModal CSS overrides from the old irma-web-* class names to the
new yivi-web-qr-code selector used by the SVG-based QR renderer.
@rubenhensen rubenhensen merged commit 5e19b94 into master Jun 18, 2026
7 checks passed
@rubenhensen rubenhensen deleted the chore/fix-dependabot-client-vulns branch June 18, 2026 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant