Bump NPM version and configure it to be more secure against supply chain attacks#1694
Bump NPM version and configure it to be more secure against supply chain attacks#1694sequba wants to merge 6 commits into
Conversation
✅ Deploy Preview for hyperformula-dev-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Performance comparison of head (06b351a) vs base (72205bd) |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 06b351a. Configure here.
| # Pin exact versions (no ^ or ~) so installs are deterministic | ||
| save-exact=true | ||
| # Enforce the Node/npm range declared in package.json "engines" | ||
| engine-strict=true |
There was a problem hiding this comment.
Engine strict without engines
Medium Severity
This commit enables engine-strict=true to enforce Node/npm ranges from package.json, but package.json has no engines field. The node/npm constraints exist only under the root entry in package-lock.json, which npm does not use for engine checks, so installs are not blocked on unsupported runtimes despite the stated hardening.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 06b351a. Configure here.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1694 +/- ##
========================================
Coverage 97.16% 97.16%
========================================
Files 176 176
Lines 15322 15322
Branches 3387 3387
========================================
Hits 14887 14887
Misses 435 435 🚀 New features to boost your workflow:
|
| package-lock=true | ||
| # Dependency cooldown: only install versions published more than N days ago | ||
| # (requires npm >= 11.10.0; silently ignored on older npm) | ||
| min-release-age=30 |
There was a problem hiding this comment.
min-release-age requires npm ≥ 11.10.0 (npm/cli#8965); older npm just prints npm warn Unknown project config 'min-release-age' and silently ignores it. Since engines was (rightly) dropped from package.json, nothing now guarantees contributors/CI actually run a new-enough npm — so this cooldown, which is the headline mitigation of this PR, may be a no-op for most installs.
Worth decoupling the two concerns: keeping engines out of the published package is correct (it shouldn't constrain library consumers), but the dev/CI npm version is separate — pinning it via .nvmrc / a packageManager field / a CI check would make min-release-age actually take effect. (The npm-version dependency is a practical inference, not npm-documented.)
There was a problem hiding this comment.
Separately, on the value itself: is 30 days heavier than needed? The cooldown analysis behind this feature found 8/10 major npm supply-chain attacks had exploitation windows under a week, so min-release-age=7 would capture ~all the protection with much less friction — relevant if the cooldown applies to npm ci (lockfile installs), since a dependency bump would then block CI until the newly-locked version ages past 30 days. Worth considering 7.
| * `npm run bundle:typings` - generates TypeScript typing, only emits ‘.d.ts’ declaration files | ||
|
|
||
| We use the Node 22 LTS in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported. | ||
| We use the Node 26 LTS in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported. |
There was a problem hiding this comment.
Small factual nit: Node 26 is on the Current line, not LTS — it does not enter LTS until ~October 2026 (released 2026-05-05). The previous "Node 22 LTS" wording was accurate (22 is Active LTS). Suggest avoiding the LTS label until it lands:
| We use the Node 26 LTS in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported. | |
| We use Node 26 (Current) in the build-chain and recommend this version for building. Note that for using (not building) HyperFormula, a wider range of Node versions is supported. |
| # Run only minimal lifecycle scripts; block arbitrary install scripts from deps | ||
| ignore-scripts=true | ||
| # Fail install if a package has a known advisory at/above this level | ||
| audit-level=low |
There was a problem hiding this comment.
Wording nit: audit-level doesn't gate npm install — it sets the exit-code threshold for npm audit. npm install prints an audit summary but won't fail on advisories. The real gate here is the Security workflow running npm run audit (= npm audit --omit=dev), which does respect this threshold. So the setting is effective, just via the audit job rather than installs.
Suggest rewording so it doesn't imply installs are blocked, e.g.:
| audit-level=low | |
| # Threshold at/above which `npm audit` (run by the Security CI workflow) fails | |
| audit-level=low |


Context
Security hardening + maintenance for the npm setup:
.npmrcto reduce supply-chain risk and make installs reproducible..nvmrc, and docs.full-icudependency (Node ships full ICU built-in).Changes
1. npm supply-chain hardening
New
.npmrcignore-scripts=truepre/post-installlifecycle scripts from dependencies — the most common malware vector.audit-level=lownpm audit.package-lock=truemin-release-age=30save-exact=true^/~) for deterministic installs.2. Default Node version → 26
.nvmrc:v18→v26test,lint,audit,build-docs,publish,performance): Node22→26build.ymlmatrix:[20, 22, 24]→[22, 24, 26](consistent withengines.node >=22)docs/guide/building.md: build-chain recommendation updated to Node 263. Remove
full-icufull-icudevDependency.NODE_ICU_DATA=node_modules/full-icufromtest:jestandtest:ciscripts.full-icuwas dead weight (and itspostinstallwas incompatible withignore-scripts=true).Notes / caveats for reviewers
min-release-ageis best-effort: only active on npm ≥ 11.10.0. Withengines.npm >=10, environments on npm 10 silently skip the cooldown. Bumpengines.npmto>=11.10.0if enforcement everywhere is desired.min-release-age=30is aggressive: installs may reject very recent dependency releases until they age in; expect friction right after dependency bumps.ignore-scripts=trueis repo-wide: affects all contributors/CI.full-icuscript concern is resolved by removing the package.esbuild(transitive, VuePress docs) ships its binary viaoptionalDependencies, so docs builds appear to work without itspostinstall— verify with a cleanrm -rf node_modules && npm ciacross all OSes before relying on it.setup-nodecan resolve Node 26 and thatbuilding.md's "LTS" wording fits the release timeline.How did you test your changes?
rm -rf node_modules && npm cilocallynpm run test:jestpasses withoutNODE_ICU_DATA(ICU-dependent tests still green) locallynpm run buildpasses on Node 26 locallybuild.ymlmatrix (Node 22/24/26, all OSes, bothnpm iandnpm ci)Note
Medium Risk
ignore-scriptsandmin-release-agecan break installs or block fresh dependency versions; Node 26 and droppingfull-icuneed CI/matrix validation across OSes andnpm ivsnpm ci.Overview
Adds a committed
.npmrcthat tightens installs:ignore-scripts=true, stricteraudit-level, lockfile enforcement,min-release-age=30,save-exact, andengine-strict.Node 26 becomes the default for
.nvmrc, most GitHub Actions workflows, anddocs/guide/building.md; thebuild.ymlmatrix shifts from[20, 22, 24]to[22, 24, 26].Removes the
full-icudevDependency and dropsNODE_ICU_DATAfromtest:jest/test:ci, relying on Node’s built-in ICU.package-lock.jsonreflects the dependency removal plus minor transitive updates and documentsengines(node >=22,npm >=10) at the lockfile root.Reviewed by Cursor Bugbot for commit 06b351a. Bugbot is set up for automated code reviews on this repo. Configure here.