fix(cli): fix hanging tests and harden shim against self-exec loop#1820
Conversation
test_check_dev_engines_sync_warns_without_tty blocked forever on read_line when the suite ran from an interactive terminal because check_dev_engines_sync read stdin TTY-ness internally. Inject the interactivity flag from the call site instead, and cover the force and satisfied paths. detect_system_node_version_returns_version hung intermittently: it spawns node, which resolves to the vp shim, while concurrent #[serial] tests mutate PATH/VP_HOME process-wide. With VP_HOME pointing elsewhere, find_system_tool failed to filter the shim's own bin dir, so the shim resolved itself as the system node and exec'd itself in an infinite loop at 100% CPU. Run the test serially, skip the running executable's directory in the PATH scan, and never return a path that canonicalizes to the running executable.
✅ Deploy Preview for viteplus-preview canceled.
|
… output pnpm's non-interactive reporter prints "[WARN] GET <url> error (ECONNRESET). Will retry in 10 seconds." while the TTY reporter pads a plain WARN with a thin space (U+2009). The snap normalizer only matched the thin-space form, so the bracketed variant leaked into command-outdated-pnpm11/snap.txt. Match both forms, write the thin space as a visible \u2009 escape, and drop the leaked line.
checkNpmPackageExists builds its URL from getNpmRegistry, which reads the developer's real .npmrc, so the registry URL assertions failed for anyone using a custom mirror registry. Partially mock npm-config to pin the public registry while keeping fetchNpmResource real.
pnpm now prints "Lockfile passes supply-chain policies" during install, which shows up in the auto-create-package-json snap outputs.
|
@cursor review |
|
@codex review |
There was a problem hiding this comment.
✅ 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 c3ccdcb. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c3ccdcbe1c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Review cleanup: find_system_tool had a third ad-hoc check in the PATH filter closure; pushing the running executable's directory into bypass_paths keeps a single exclusion mechanism. The canonicalize backstop for symlinked shims is unchanged.
Generalize the [WARN]-or-thin-space prefix from the GET retry rule to the Skip adding, Request took, Issue while reading, and Tarball download rules so the bracketed non-interactive form cannot leak through a sibling rule. This exposed that the Tarball rule never matched its own test fixture: the committed snapshot had blessed the warning lines passing through unstripped. The broadened prefix makes the rule work; the fixture gains a trailing line so the regenerated snapshot proves both lines are stripped.
Codex review: the canonicalize backstop returned None as soon as the first resolved candidate was the running executable, so a real system tool later in PATH (e.g. /usr/bin/node) was never considered and bypass or system-first mode failed even though a valid tool existed. Drop the self candidate's directory and retry resolution with the remaining PATH instead. Adds a symlink-based regression test.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 599f46cf7a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Codex round-two review: - Do not pre-exclude current_exe's directory from the PATH scan: when vp is installed next to a real tool in a shared bin dir (e.g. /usr/local/bin/vp beside /usr/local/bin/node), that exclusion hid the adjacent real tool. The canonicalized per-candidate identity check already rejects only the shim itself. - Resolve relative PATH entries against cwd before searching: which reports matches from relative entries as relative paths, which AbsolutePathBuf rejects, so resolution failed outright (pre-existing) and the self-skip retry loop could not drop the matching entry. Tilde entries are left to which's own expansion. Adds a relative-PATH-entry self-symlink regression test.
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…ss cwd The relative-PATH-entry regression test used set_current_dir, which can race with unannotated tests in the same binary (#[serial] only serializes against other serial tests). Split out find_system_tool_in taking cwd as a parameter (its only job is absolutizing relative PATH entries) and pass the temp dir explicitly, so the process working directory is never touched. Also dedupes the shared symlink test setup into a helper.
main's #1820 regenerated these snaps against pnpm >= 10.34.3 and committed its new '✓ Lockfile passes supply-chain policies' status line; the snap scrubber now strips that line at runtime, so the committed snaps must not contain it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
main's #1820 regenerated these snaps against pnpm >= 10.34.3 and committed its new '✓ Lockfile passes supply-chain policies' status line; the snap scrubber now strips that line at runtime, so the committed snaps must not contain it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Problem
Two tests in
vite_global_clican hang forever:commands::env::pin::tests::test_check_dev_engines_sync_warns_without_tty:check_dev_engines_syncchecksstdin().is_terminal()internally, so when the suite runs from an interactive terminal the test blocks onread_linewaiting for keyboard input.commands::version::tests::detect_system_node_version_returns_version(intermittent): it spawnsnode, which resolves to the vp shim, while concurrent#[serial]tests mutatePATH/VP_HOMEprocess-wide. WithVP_HOMEpointing elsewhere,find_system_toolfails to filter the shim's own bin dir, so the shim resolves itself as the system node and exec's itself in an infinite loop at 100% CPU.Fix
check_dev_engines_syncas a parameter computed at the call site, so tests exercise the non-TTY and--forcepaths deterministically (new force-path test included).detect_system_node_version_returns_versionas#[serial]so no other test mutates the process env while it spawnsnode.find_system_tool: skip the running executable's directory in the PATH scan, and never return a path that canonicalizes to the running executable. This also protects real users from the self-exec spin (e.g. mis-setVP_HOMEwith~/.vite-plus/binon PATH).Full suite: 1492 tests pass with no hangs, clippy and rustfmt clean.
Also includes
[WARN] GET <registry url> ... Will retryretry lines (the existing rule only matched the TTY thin-spaceWARNform, now written as a visible\u2009escape).package.spec.ts: pingetNpmRegistryvia partial mock so registry URL assertions pass for developers using a mirror registry.Note
Medium Risk
Shim PATH filtering changes real bypass/system-first behavior (intended fix for infinite exec); pin UX is unchanged at the call site but the devEngines sync path is user-facing when pinning.
Overview
Fixes hanging and flaky
vite_global_clitests and shim self-exec loops when PATH resolution picks up the vp shim instead of realnode.check_dev_engines_syncnow takes an explicitinteractiveflag (from stdin TTY at the pin call site) instead of callingstdin().is_terminal()inside the helper, so tests can force non-TTY and--forcebehavior without blocking on input. New coverage asserts--forceskips prompts even wheninteractiveis true.find_system_toolexcludes the running shim’s directory from PATH scanning and refuses a resolved path that canonicalizes tocurrent_exe(), closing loops whenVP_HOMEand the shim on PATH disagree (including symlink edge cases).detect_system_node_version_returns_versionruns under#[serial]so concurrent tests mutatingPATH/VP_HOMEdo not break the spawnednodeprobe.Smaller fixes: snap normalizer strips pnpm
[WARN] GET …retry lines;package.spec.tsmocksgetNpmRegistryfor mirror setups; install snap fixtures include pnpm’s supply-chain lockfile line.Reviewed by Cursor Bugbot for commit c3ccdcb. Configure here.