Skip to content

feat(pm): support npm approve-scripts/deny-scripts in approve-builds#1733

Merged
fengmk2 merged 3 commits into
mainfrom
feat/npm-approve-scripts
Jun 2, 2026
Merged

feat(pm): support npm approve-scripts/deny-scripts in approve-builds#1733
fengmk2 merged 3 commits into
mainfrom
feat/npm-approve-scripts

Conversation

@fengmk2

@fengmk2 fengmk2 commented Jun 1, 2026

Copy link
Copy Markdown
Member

Summary

npm 11.16.0 (npm/cli#9360, "Phase 1 of allowScripts opt-in install-script policy") adds npm approve-scripts and npm deny-scripts, which manage an advisory allowScripts field in package.json. This is the npm equivalent of pnpm approve-builds / bun pm trust.

vp pm approve-builds previously warned and exited 0 (no-op) on npm. It now forwards to npm's real commands when the detected npm is >= 11.16.0.

Mapping (npm >= 11.16.0)

vp pm approve-builds invocation npm command
<pkg>... (approves) npm approve-scripts <pkg>...
--all npm approve-scripts --all
(no args) npm approve-scripts --allow-scripts-pending (read-only list)
!<pkg>... (denies, ! stripped) npm deny-scripts <pkg>...
mixed approves + !denies rejected with an actionable error
npm < 11.16.0 warn + exit 0 (no-op), advise upgrade

Notes

  • Mixed approve+deny is rejected rather than silently split: npm separates approve vs. deny into two commands, so vp pm approve-builds esbuild !core-js returns a clear message asking the user to run the two operations separately (pnpm handles the mixed case in one command). This keeps the single-command return type intact.
  • Advisory caveat surfaced: npm 11.x's allowScripts is advisory only (install scripts still run; npm just warns about unreviewed packages). A one-line note is shown after an approve/deny write so users aren't misled. Not shown on the read-only --allow-scripts-pending listing.
  • Version gating reuses the existing version_satisfies/node_semver pattern (npm_supports_allow_scripts = >=11.16.0), matching pnpm's prerelease semantics.
  • Help text for the deny prefix and --all updated from "pnpm only" to reflect pnpm + npm support.

Tests

  • 9 new unit tests in approve_builds.rs (approve-by-name, --all, pending-list, deny-only, multi-deny, mixed-rejected, pass-through, below-gate no-op, prerelease no-op). The Option return type is unchanged, so existing tests are untouched.
  • New global snap test command-pm-approve-builds-npm11/ (npm@11.16.0) exercising the real npm commands end-to-end.
  • 4 existing approve-builds snaps regenerated for the help-text wording change and the updated npm warn message.

Validation

  • cargo test -p vite_install -p vite_pm_cli (510 passed)
  • just check
  • cargo clippy -p vite_install -p vite_pm_cli -- -D warnings
  • pnpm bootstrap-cli + local/global approve-builds snap tests regenerated and reviewed

Note

Low Risk
Changes are localized to PM command resolution and user messaging; npm below 11.16.0 and yarn/pnpm/bun paths stay the same aside from help text.

Overview
vp pm approve-builds now forwards to npm on npm ≥ 11.16.0 instead of always warning and no-op’ing. Older npm still gets the legacy warn + exit 0, with copy that mentions upgrading to 11.16.0.

For supported npm versions, invocations map to npm approve-scripts (packages, --all, or no-args → --allow-scripts-pending pending list) and npm deny-scripts when only !pkg tokens are passed (! stripped). Mixed approve + deny in one call is rejected with guidance to run two separate commands. Package names passed only after -- on the pending-list path are also rejected.

After writes that change allowScripts, a note explains npm 11.x policy is advisory (scripts still run; enforcement is future). Pass-through args are forwarded on the npm path like pnpm/bun.

CLI help and the approve-builds RFC are updated for pnpm + npm parity on !pkg, --all, and no-args behavior. Coverage adds many npm 11.16 unit tests, a global snap fixture for npm@11.16.0, and regenerated snaps for help/warn text.

Reviewed by Cursor Bugbot for commit 2a34ce3. Configure here.

@fengmk2 fengmk2 self-assigned this Jun 1, 2026
@netlify

netlify Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deploy Preview for viteplus-preview ready!

Name Link
🔨 Latest commit 18c50f9
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a1e514d8a61c90008642feb
😎 Deploy Preview https://deploy-preview-1733--viteplus-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

npm 11.16.0 (npm/cli #9360) adds `approve-scripts` and `deny-scripts`
commands that manage an advisory `allowScripts` field in package.json.
`vp pm approve-builds` previously warned and no-oped on npm; it now
forwards to these commands when npm >= 11.16.0:

- approves     -> npm approve-scripts <pkg...>
- --all        -> npm approve-scripts --all
- no args      -> npm approve-scripts --allow-scripts-pending (list pending)
- !pkg denies  -> npm deny-scripts <pkg...> (the `!` is stripped)

Mixed approve+deny in a single invocation is rejected with an actionable
message, since npm splits the two operations into separate commands.
A one-line note is shown after a write because npm 11.x's allowScripts
is advisory (install scripts still run). npm < 11.16.0 keeps the
warn + exit-0 no-op, now pointing at the upgrade.
@fengmk2 fengmk2 force-pushed the feat/npm-approve-scripts branch from b690672 to 4e25692 Compare June 1, 2026 05:41
- reject a positional passed via `--` on npm's read-only pending path
  instead of building an invalid `npm approve-scripts --allow-scripts-pending <pkg>`
- collapse the three duplicated advisory-note calls into a single `writes_policy` gate
- fix the now-stale pass-through comment (npm also reaches the shared tail)
- update RFC section 4, which no longer applies to npm >= 11.16.0

Adds unit tests for the pending guard (rejects positionals, still forwards flags)
and a snap-test step covering the rejection.
@fengmk2

fengmk2 commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

@cursor review

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 2a34ce3. Configure here.

@fengmk2 fengmk2 marked this pull request as ready for review June 2, 2026 03:43
@fengmk2 fengmk2 requested a review from cpojer June 2, 2026 03:43
@fengmk2 fengmk2 merged commit 8543be7 into main Jun 2, 2026
40 checks passed
@fengmk2 fengmk2 deleted the feat/npm-approve-scripts branch June 2, 2026 05:39
@fengmk2 fengmk2 mentioned this pull request Jun 17, 2026
fengmk2 added a commit that referenced this pull request Jun 17, 2026
Release vite-plus v0.2.0.

Vite+ now consumes upstream Vitest directly (no wrapper), raises the
minimum supported Node.js version to 22.18.0, and ships corepack and
devEngines support.

### Highlights

- **`vp test` now runs upstream Vitest directly (breaking)**: Vite+ used
to ship `@voidzero-dev/vite-plus-test`, a rebundled copy of Vitest that
lagged upstream releases. That package is removed; `vp test` now runs
the real upstream `vitest`, which is installed automatically as a
dependency of `vite-plus` (you no longer add `vitest` or `@vitest/*`
yourself, and `vite` still resolves to `@voidzero-dev/vite-plus-core`
via package-manager overrides). Your `import ... from 'vite-plus/test'`
code keeps working unchanged and `vp migrate` updates existing projects
([#1588](#1588)), by
@Brooooooklyn
- **Minimum supported Node.js version raised to `^22.18.0 || >=24.11.0`
(breaking)**: Node 20 reached end-of-life and the bundled tsdown already
required `^22.18.0`, so the published engines range now matches what `vp
pack` can actually deliver; `vp exec` / `vp run` / `vp dlx` reject
projects resolving an older Node with the existing incompatibility error
([#1813](#1813)), by
@fengmk2
- **Corepack now works under Vite+**: `corepack` is a default `vp env
setup` shim, resolved managed-global, then Node-bundled (Node <= 24),
then auto-installed (Node 25+, which dropped corepack); `corepack
enable` / `disable` land their pnpm/yarn launchers on PATH and
Vite+-owned shims are restored if corepack replaces them
([#1808](#1808)), by
@fengmk2
- **devEngines support for runtime and package-manager selection**:
Vite+ reads `devEngines.runtime` (ranked above `engines.node`) and
`devEngines.packageManager`; auto-pin and `vp migrate` write
`devEngines.packageManager`, `vp env pin` / `unpin` target
`devEngines.runtime`, and `vp env doctor` reports conflicts instead of
silently resolving them
([#1760](#1760)), by
@fengmk2

### Features

- `vp pm approve-builds`: forward to npm's new `approve-scripts` /
`deny-scripts` (npm >= 11.16.0) instead of the previous no-op, matching
`pnpm approve-builds` / `bun pm trust`; mixed approve+deny is rejected
with actionable guidance and npm's advisory-only caveat is surfaced
([#1733](#1733)), by
@fengmk2
- `vp create`: support local monorepo templates declared in
`create.templates` in `vite.config.ts`; `vp create vite:generator`
scaffolds a Bingo generator and auto-registers it in the picker,
replacing the old package.json-keyword inference
([#1777](#1777)), by
@fengmk2
- `vp create`: detect direct dependencies whose build scripts the
package manager gated (e.g. native builds like `better-sqlite3`) and act
on them; prompt to approve each (default off) interactively, point at
`vp pm approve-builds` non-interactively, or build them with
`--approve-builds`
([#1828](#1828)), by
@fengmk2
- `vp config`: add `--no-hooks` and `--no-agent` opt-outs to skip
git-hook installation and coding-agent instruction updates
([#1842](#1842)), by
@leno23
- `vp list -g`: sort the global package list output so entries appear in
a stable order
([#1748](#1748)), by
@liangmiQwQ
- Upgrade upstream dependencies: rolldown `1.0.3 -> 1.1.1`, tsdown
`0.22.1 -> 0.22.3`, oxlint `1.67.0 -> 1.70.0`, oxfmt `0.52.0 -> 0.55.0`,
vitest `4.1.8 -> 4.1.9`, and the oxc toolchain `0.133.0 -> 0.136.0`
([#1749](#1749),
[#1767](#1767),
[#1812](#1812),
[#1834](#1834),
[#1855](#1855)), by
@voidzero-guard[bot]

### Fixes & Enhancements

- Security: resolve open Rust Dependabot advisories by bumping
transitive `openssl` `0.10.76 -> 0.10.80` (`openssl-sys` `0.9.112 ->
0.9.116`), fixing five high-severity rust-openssl issues (buffer
overflows in key derivation, AES key wrap, and digest finalization; an
unchecked PSK/cookie trampoline length leaking adjacent memory; and
OCSP-responder undefined behavior:
[GHSA-pqf5-4pqq-29f5](GHSA-pqf5-4pqq-29f5),
[GHSA-8c75-8mhr-p7r9](GHSA-8c75-8mhr-p7r9),
[GHSA-ghm9-cr32-g9qj](GHSA-ghm9-cr32-g9qj),
[GHSA-hppc-g8h3-xhp3](GHSA-hppc-g8h3-xhp3),
[GHSA-xp3w-r5p5-63rr](GHSA-xp3w-r5p5-63rr)),
and drop the unmaintained, unsound `libyml`
([GHSA-gfxp-f68g-8x78](GHSA-gfxp-f68g-8x78),
high) by removing dead `serde_yml` code
([#1742](#1742)), by
@fengmk2
- Security (docs site): update `mermaid` `11.13.0 -> 11.15.0` to fix
improper `classDef` sanitization in state diagrams that allowed HTML
injection
([CVE-2026-41149](https://nvd.nist.gov/vuln/detail/CVE-2026-41149) /
[GHSA-ghcm-xqfw-q4vr](GHSA-ghcm-xqfw-q4vr),
medium severity; `<script>` tags are stripped so it does not reach XSS)
([#1745](#1745)), by
@renovate[bot]
- `vp check --fix` / `vp staged`: create/migrate now wrap inline Vite
`plugins: [...]` arrays with `lazyPlugins(...)` so plugin factories
aren't eagerly executed (and don't hang on open handles) during
lint/format/check config loading
([#1752](#1752)), by
@jong-kyung
- `vp migrate`: complete pending migration work for projects that
already have `vite-plus` installed (scripts, imports, tsconfig types,
ESLint/Prettier, legacy hooks, package-manager settings) instead of
treating `vite-plus` as migration-complete; fully migrated projects stay
idempotent
([#1821](#1821)), by
@jong-kyung
- `vp create` / `vp migrate`: detect shorthand `fmt,` / `lint,` config
keys so a duplicate inline block is no longer injected
([#1843](#1843)), by
@fengmk2
- IDE oxlint/oxfmt wrappers: set `VP_COMMAND` so `lazyPlugins()` skips
framework plugins during LSP config reads, preventing a stray
`.svelte-kit` (and similar) directory at the monorepo root
([#1764](#1764)), by
@jong-kyung
- `vp lint` / `vp run -r lint` on Windows: keep the absolute `tsgolint`
path for workspace lint runs instead of downgrading it to a wrong
cwd-relative path
([#1758](#1758)), by
@semimikoh
- oxlint wrapper: set the `tsgolint` path so type-aware lint resolves it
([#1811](#1811)), by
@jong-kyung
- `vp install -g`: use a unique backup directory and treat stale-backup
cleanup as best-effort so a locked Windows binary no longer fails an
otherwise successful reinstall
([#1753](#1753)), by
@fengmk2
- `vp install -g`: remove stale managed binary shims when a reinstalled
package drops a bin from its `package.json#bin`
([#1765](#1765)), by
@liangmiQwQ
- `vp create --git`: surface git's actual stdout/stderr when the initial
commit fails instead of always blaming `user.name` / `user.email`
([#1819](#1819)), by
@fengmk2
- `vp create vite:generator`: reject `--git` / `--no-git`, since adding
a generator to an existing monorepo does not initialize git
([#1788](#1788)), by
@jong-kyung
- Global CLI: harden `find_system_tool` against a self-exec loop (skip
the running executable's own bin directory) and fix two
`vite_global_cli` tests that could hang
([#1820](#1820)), by
@fengmk2
- CLI help: unify alias display
([#1832](#1832)), show
supported `run` options
([#1797](#1797)), show
`--fail-if-no-match` in `exec` help
([#1798](#1798)), add the
`implode` documentation link
([#1796](#1796)), and
handle nested-command typo help
([#1803](#1803)), by
@jong-kyung

### Docs

- Document `vp create` opt-out options
([#1790](#1790)), by
@jong-kyung
- Document `vp upgrade` options
([#1847](#1847)), by
@jong-kyung
- Align the config overview with the sidebar
([#1846](#1846)), by
@jong-kyung
- Sync the documented command lists with the help output
([#1850](#1850)), by
@jong-kyung
- Clarify lazy plugin side effects
([#1841](#1841)), by
@leno23
- Add JongKyung's X profile
([#1844](#1844)) and
update Christoph's X profile
([#1845](#1845)) on the
team page, by @jong-kyung

### Refactor

- Remove the CLI tips system; the shortcuts it printed on `vp install`
are already covered by the help system and added unnecessary complexity
([#1799](#1799)), by
@cpojer

### Chore

- Re-enable Renovate dependency updates with a targeted ignore-list
([#1744](#1744)), by
@fengmk2
- Keep generated NAPI bindings during upgrade-deps
([#1759](#1759)), by
@fengmk2
- Remove the `vite_glob` dependency from vite-plus
([#1763](#1763)), by
@wan9chi
- Keep `sync-remote` from churning `pnpm-workspace.yaml` (dedupe
`minimumReleaseAgeExclude`, preserve comments)
([#1787](#1787)), by
@fengmk2
- Make unix `just test` runnable
([#1755](#1755)), by
@situ2001
- CI: reuse `just lint` and `just test` as the single source of truth
([#1809](#1809)), pin
`cargo-zigbuild` to a git rev to fix the aarch64-musl link failure
([#1815](#1815)), and keep
upgrade-deps green when rolldown bumps oxc
([#1833](#1833)), by
@fengmk2
- Update Rust to nightly-2026-06-10
([#1725](#1725)), typos to
v1.47.1 / v1.47.2
([#1772](#1772),
[#1775](#1775)), GitHub
Actions ([#1778](#1778),
[#1829](#1829)), and npm
packages ([#1779](#1779)),
by @renovate[bot]
- Bump `oxc-project/setup-node` to v1.3.1
([#1792](#1792)), by
@Boshen
- Refresh trusted stack stats on the docs homepage
([#1786](#1786),
[#1837](#1837)), by
@voidzero-guard[bot]

### Bundled Versions

| Tool | Version | Source |
| --- | --- | --- |
| vite | `8.0.16` |
[`f94df87`](vitejs/vite@f94df87)
|
| rolldown | `1.1.1` |
[`d7f919c`](rolldown/rolldown@d7f919c)
|
| tsdown | `0.22.3` | [npm](https://npmx.dev/package/tsdown/v/0.22.3) |
| vitest | `4.1.9` | [npm](https://npmx.dev/package/vitest/v/4.1.9) |
| oxlint | `1.70.0` | [npm](https://npmx.dev/package/oxlint/v/1.70.0) |
| oxlint-tsgolint | `0.23.0` |
[npm](https://npmx.dev/package/oxlint-tsgolint/v/0.23.0) |
| oxfmt | `0.55.0` | [npm](https://npmx.dev/package/oxfmt/v/0.55.0) |

### Upgrading from 0.1.24 to 0.2.0

This release has two breaking changes. For most projects the upgrade is
`vp upgrade`, bump the project's `vite-plus`, then `vp migrate`.

#### 1. Update the CLI

```bash
vp upgrade
```

#### 2. Node.js 20 is no longer supported

The minimum supported Node.js version is now `^22.18.0 || >=24.11.0`
(Node 20 reached end-of-life). If you are still on Node 20:

- Check your version: `node --version` (or `vp env doctor`)
- Move to a supported release: `vp env pin 22.18.0` (or a newer LTS), or
update your `.node-version` / `devEngines.runtime`

`vp exec` / `vp run` / `vp dlx` now refuse to run against a project that
resolves Node < 22.18.0.

#### 3. Vitest is now upstream (the wrapper is gone)

`@voidzero-dev/vite-plus-test` has been removed; Vite+ consumes upstream
`vitest` directly. Bump `vite-plus` first, then migrate:

```bash
vp update vite-plus --latest    # project's vite-plus -> 0.2.0 (ignores the old range, updates the lockfile); monorepo: add -r
vp migrate                      # local vite-plus is now 0.2.0, so the new migration runs
```

`vp update --latest` re-resolves `vite-plus` to the newest release
regardless of the old semver range, so the lockfile cannot pin you back
to 0.1.24. The project's local `vite-plus` is then 0.2.0, and since the
global `vp` delegates `migrate` to the project's local install, `vp
migrate` runs the new migration.

- Your `import { vi, ... } from 'vite-plus/test'` code is unchanged. `vp
migrate` rewrites any leftover `vitest` / `@vitest/*` imports and
normalizes stale `vitest: npm:@voidzero-dev/vite-plus-test@*` aliases.
- You no longer add `vitest` or `@vitest/*` yourself; they arrive
transitively through `vite-plus`.

### New Contributors

Welcome to our new contributor @situ2001! 🎉

**Full Changelog**:
v0.1.24...v0.2.0

---

Merging this PR will trigger the release workflow.

---------

Co-authored-by: voidzero-guard[bot] <278573678+voidzero-guard[bot]@users.noreply.github.com>
Co-authored-by: MK <fengmk2@gmail.com>
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