Skip to content

Resolve security advisories - #30

Merged
mvantellingen merged 8 commits into
masterfrom
security-updates
Oct 25, 2026
Merged

mvantellingen merged 8 commits into
masterfrom
security-updates

Conversation

@mvantellingen

@mvantellingen mvantellingen commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Resolve security advisories, require Node 22, switch to tsdown

Security fix

  • form-data 4.0.0 -> 4.0.6. It is a transitive dev dependency (jest-environment-jsdom -> jsdom@19). This resolves the critical Dependabot alert (vulnerable >= 4.0.0, < 4.0.4). It was fixed with an in-range lockfile update, so no override was needed.

Breaking: Node.js >= 22

  • engines.node: >=16.0.0 -> >=22.0.0 (Node 20 is EOL).
  • CI (main.yml): Node 20 -> matrix of Node 22 and 24.
  • Publish (publish.yml): Node 20 -> 24.
  • Released as a minor changeset.

Build: tsup -> tsdown

  • Replaced tsup@6 with tsdown@^0.23.1. Config is in tsdown.config.mts (esm + cjs, dts, sourcemaps, fixedExtension: false, target es2020).
  • typescript 4.7 -> 5.9, because tsdown's dts generation requires TS >= 5.
  • @types/node (transitive) 18.7 -> 26.6. The old version does not typecheck under TS 5.9.
  • dist file list:
    • before: index.js, index.js.map, index.mjs, index.mjs.map, index.d.ts
    • after: the same files plus index.d.mts
    • main, module and typings in package.json still point to existing files.
  • react, react-dom/client and tiny-current-script remain external. Both require('./dist/index.js') and import('./dist/index.mjs') expose the same 6 exports.
  • Minor cosmetic difference: the generated .d.ts has a trailing sourceMappingURL comment with no .d.ts.map file. This is harmless.

Actions pinning

  • pinact run: no changes. All actions were already pinned to SHAs.

Verification (local, Node 24)

  • pnpm install --frozen-lockfile --ignore-scripts: OK. Scripts are skipped because the root preinstall runs npx only-allow pnpm.
  • pnpm lint: 0 errors, 9 warnings (same as master).
  • pnpm exec tsc --noEmit -p .: OK.
  • pnpm build (tsdown): OK.
  • Consumer typecheck of dist/index.d.ts under --strict: OK.
  • pnpm test: fails with TypeError: Cannot read properties of null (reading 'querySelectorAll') in a MutationObserver callback. This is pre-existing: master fails the same way, and CI runs tests with continue-on-error: true.

Alerts not resolved

  • None.

Notes

  • The preinstall script still uses npx only-allow pnpm. Consider replacing it, e.g. with packageManager + corepack, or by dropping it.
  • packageManager is still pnpm@9.7.0.
  • @typescript-eslint 5.33 officially supports TS < 4.8. Lint runs fine with TS 5.9, but it may print a version-support warning.

Vitest

  • Replaced jest, ts-jest, jest-environment-jsdom and @types/jest with vitest 5.0.5 and jsdom 30.1.3. jest.config.ts is gone; vitest.config.mts sets the jsdom environment.
  • test/test:watch now run vitest run/vitest. Tests import describe/it/expect/vi from vitest, and jest.spyOn became vi.spyOn.
  • The test suite passes: 15 passed, 4 skipped (they were already it.skip). I removed continue-on-error: true from the CI test step, so test failures now fail CI again.
  • Fixed the uses JSON.parse as a custom prop parser test. It called populate() 100 times without awaiting it and checked the result in a .then() after the test had already finished, so it never asserted anything. Even with a wrong expected value it passed. Those leftover callbacks also caused the jest crash on master (Cannot read properties of null (reading 'querySelectorAll')): a MutationObserver fired after the jsdom environment was torn down. The test now uses fc.asyncProperty and awaits each step. It passes, and it fails if the expected value is wrong.
  • Known issue, not fixed here: every populate() call adds a new MutationObserver on document.body and never disconnects it, so calling populate() more than once leaves extra observers behind and repeats work on every DOM change.

pnpm

  • Moved packageManager from pnpm@9.7.0 to pnpm@12.15.0 and set engines.pnpm to >=12.
  • Removed the preinstall: npx only-allow pnpm script. pnpm is now enforced by packageManager, engines.pnpm and engineStrict: true.
  • pnpm 12 no longer reads pnpm settings from .npmrc or resolutions from package.json. I moved autoInstallPeers and the serialize-javascript override to a new pnpm-workspace.yaml and deleted .npmrc.
  • The lockfile is still lockfileVersion: '9.0' and every package version is the same. pnpm 12 added a document at the top that pins pnpm itself, plus supports-color peer suffixes on debug/eslint entries.

Org-enforced workflows

  • Removed the repo-local pinact, zizmor and other security workflows. These checks now run as org-wide required workflows from labd/.github-workflows, so keeping copies in this repo would only run them twice.

Node 26

Adds Node 26 to the CI test matrix: 22, 24 → 22, 24, 26. Publish/release jobs are unchanged and stay on a single LTS. Verified locally on Node 26.3.0 (install + CI test steps pass).

npm trusted publishing

The org-level NPM_TOKEN secret is gone, so publish.yml now publishes through npm trusted publishing (OIDC), following labd/commercetools-node-mock.

  • publish.yml: workflow default contents: read; the job uses environment: release and id-token: write, and checkout uses persist-credentials: false
  • Removes registry-url and NODE_AUTH_TOKEN; upgrades npm to ^11.6.4 (trusted publishing needs npm >= 11.5.1) and publishes with NPM_CONFIG_PROVENANCE: true
  • package.json: repository.url is now git+https://github.com/labd/react-abode.git; adds publishConfig (access: public, provenance: true)

Before the next release, add a trusted publisher on npmjs.com for react-abode. Use repository labd/react-abode, workflow publish.yml and environment release.

pnpm 12

  • pnpm-workspace.yaml now sets minimumReleaseAge: 20160 (14 days, verified with pnpm config get minimumReleaseAge).
  • pnpm 12 applies minimumReleaseAge to its own version as well, so packageManager moves from pnpm@12.15.0 (4 days old) to pnpm@12.12.0, the newest 12.x that is older than 14 days.
  • pnpm 12 also checks the existing lockfile against the policy, including --frozen-lockfile installs. 31 locked versions from the recent security updates are younger than 14 days. Instead of downgrading them, they're listed by exact name@version in minimumReleaseAgeExclude. Those entries can be removed after 2026-11-04.
  • Lockfile: only the packageManagerDependencies block changes (pnpm 12.15.0 → 12.12.0). No dependency versions changed.

- form-data 4.0.0 -> 4.0.6 (transitive via jest-environment-jsdom/jsdom; critical advisory, < 4.0.4)
- Require Node >= 22 (engines), CI tests on Node 22 and 24, publish on Node 24 (breaking)
- Replace tsup 6 with tsdown 0.23 (tsdown.config.mts); output names unchanged, adds dist/index.d.mts
- typescript 4.7 -> 5.9 (needed by tsdown dts generation)
- @types/node (transitive) 18.7 -> 26.6 so tsc works with TypeScript 5.9
These checks now run via the org-wide required workflows in
labd/.github-workflows.
@mvantellingen
mvantellingen merged commit 6a36eb4 into master Oct 25, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Oct 26, 2026
@mvantellingen
mvantellingen deleted the security-updates branch October 26, 2026 13:33
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