Skip to content

Bump NPM version and configure it to be more secure against supply chain attacks#1694

Open
sequba wants to merge 6 commits into
developfrom
feature/improve-npm-security
Open

Bump NPM version and configure it to be more secure against supply chain attacks#1694
sequba wants to merge 6 commits into
developfrom
feature/improve-npm-security

Conversation

@sequba

@sequba sequba commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Context

Security hardening + maintenance for the npm setup:

  1. Add a committed .npmrc to reduce supply-chain risk and make installs reproducible.
  2. Bump the default/build Node version to 26 across CI, .nvmrc, and docs.
  3. Remove the obsolete full-icu dependency (Node ships full ICU built-in).

Changes

1. npm supply-chain hardening

New .npmrc

Setting Purpose
ignore-scripts=true Blocks arbitrary pre/post-install lifecycle scripts from dependencies — the most common malware vector.
audit-level=low Surfaces advisories down to low severity in npm audit.
package-lock=true Always enforces lockfile integrity.
min-release-age=30 Dependency cooldown — only installs package versions published >30 days ago, mitigating compromised fresh releases. (Requires npm ≥ 11.10.0; silently ignored on older npm.)
save-exact=true Pins exact versions (no ^/~) for deterministic installs.

2. Default Node version → 26

  • .nvmrc: v18v26
  • All CI workflows (test, lint, audit, build-docs, publish, performance): Node 2226
  • build.yml matrix: [20, 22, 24][22, 24, 26] (consistent with engines.node >=22)
  • docs/guide/building.md: build-chain recommendation updated to Node 26

3. Remove full-icu

  • Dropped full-icu devDependency.
  • Removed NODE_ICU_DATA=node_modules/full-icu from test:jest and test:ci scripts.
  • Rationale: Node ≥ 14 bundles full ICU, and the project now requires Node ≥ 22 — so full-icu was dead weight (and its postinstall was incompatible with ignore-scripts=true).

Notes / caveats for reviewers

  • min-release-age is best-effort: only active on npm ≥ 11.10.0. With engines.npm >=10, environments on npm 10 silently skip the cooldown. Bump engines.npm to >=11.10.0 if enforcement everywhere is desired.
  • min-release-age=30 is aggressive: installs may reject very recent dependency releases until they age in; expect friction right after dependency bumps.
  • ignore-scripts=true is repo-wide: affects all contributors/CI.
    • full-icu script concern is resolved by removing the package.
    • esbuild (transitive, VuePress docs) ships its binary via optionalDependencies, so docs builds appear to work without its postinstallverify with a clean rm -rf node_modules && npm ci across all OSes before relying on it.
  • Node 26 availability: confirm the CI runner / setup-node can resolve Node 26 and that building.md's "LTS" wording fits the release timeline.

How did you test your changes?

  • rm -rf node_modules && npm ci locally
  • npm run test:jest passes without NODE_ICU_DATA (ICU-dependent tests still green) locally
  • npm run build passes on Node 26 locally
  • Docs/VuePress build passes from a clean install (esbuild works without postinstall) locally
  • CI green across the build.yml matrix (Node 22/24/26, all OSes, both npm i and npm ci)

Note

Medium Risk
ignore-scripts and min-release-age can break installs or block fresh dependency versions; Node 26 and dropping full-icu need CI/matrix validation across OSes and npm i vs npm ci.

Overview
Adds a committed .npmrc that tightens installs: ignore-scripts=true, stricter audit-level, lockfile enforcement, min-release-age=30, save-exact, and engine-strict.

Node 26 becomes the default for .nvmrc, most GitHub Actions workflows, and docs/guide/building.md; the build.yml matrix shifts from [20, 22, 24] to [22, 24, 26].

Removes the full-icu devDependency and drops NODE_ICU_DATA from test:jest / test:ci, relying on Node’s built-in ICU. package-lock.json reflects the dependency removal plus minor transitive updates and documents engines (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.

@netlify

netlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Deploy Preview for hyperformula-dev-docs ready!

Name Link
🔨 Latest commit 06b351a
🔍 Latest deploy log https://app.netlify.com/projects/hyperformula-dev-docs/deploys/6a30195854a2ad0008537205
😎 Deploy Preview https://deploy-preview-1694--hyperformula-dev-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread .npmrc
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

Performance comparison of head (06b351a) vs base (72205bd)

                                     testName |   base |   head |  change
-------------------------------------------------------------------------
                                      Sheet A | 439.47 | 439.99 |  +0.12%
                                      Sheet B | 149.96 | 148.76 |  -0.80%
                                      Sheet T |  125.6 | 121.25 |  -3.46%
                                Column ranges | 516.57 | 515.83 |  -0.14%
Sheet A:  change value, add/remove row/column |  13.36 |  11.97 | -10.40%
 Sheet B: change value, add/remove row/column | 134.29 | 125.75 |  -6.36%
                   Column ranges - add column | 161.09 | 154.48 |  -4.10%
                Column ranges - without batch | 498.04 | 488.16 |  -1.98%
                        Column ranges - batch | 123.87 | 120.82 |  -2.46%

@sequba sequba requested a review from marcin-kordas-hoc June 15, 2026 14:47
@sequba sequba changed the title Configure NPM to be more secure against supply chain attacks Bump NPM version and configure it to be more secure against supply chain attacks Jun 15, 2026
Comment thread package.json Outdated
@sequba sequba self-assigned this Jun 15, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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.

Comment thread .npmrc
# 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 06b351a. Configure here.

@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.16%. Comparing base (72205bd) to head (06b351a).

Additional details and impacted files

Impacted file tree graph

@@           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:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread .npmrc
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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread docs/guide/building.md
* `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.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Suggested change
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.

Comment thread .npmrc
# 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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.:

Suggested change
audit-level=low
# Threshold at/above which `npm audit` (run by the Security CI workflow) fails
audit-level=low

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.

2 participants