Skip to content

fix(vscode): use shell mode for spawn on Windows to detect npm correctly - #626

Closed
aalhadxx wants to merge 5 commits into
alibaba:mainfrom
aalhadxx:fix/vscode-windows-shell
Closed

fix(vscode): use shell mode for spawn on Windows to detect npm correctly#626
aalhadxx wants to merge 5 commits into
alibaba:mainfrom
aalhadxx:fix/vscode-windows-shell

Conversation

@aalhadxx

@aalhadxx aalhadxx commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Fixes #453

Problem

On Windows, child_process.spawn cannot find npm.cmd / npx.cmd without shell: true, causing the VS Code extension to falsely report npm not detected and disable CLI features.

Fix

Add shell: process.platform === 'win32' only to probeCommand (used for environment detection with hardcoded --version args). runRaw is intentionally left unchanged — it receives user-controlled args and must not use shell: true for security.

Tests

  • CliService.isAvailable — verifies node is found on Windows
  • CliService probe shell option — asserts shell: true is passed on win32 and shell: false (or absent) on Linux/macOS
  • Existing runRaw and testConnection tests remain unaffected (use real spawn)

Prior art

Supersedes #584 (closed due to merge conflicts in lock files).

aalhadxx added 4 commits July 31, 2026 12:12
On Windows, npm is shipped as npm.cmd. Without shell: true, Node's
spawn fails to execute batch files, causing the VS Code extension to
falsely report 'npm not detected' even when it is installed.

The install() method already used this flag; apply the same fix to
probeCommand (environment detection) and runRaw (CLI execution).

Fixes alibaba#453
Reverts shell: true in runRaw to address security feedback:
runRaw args may include user-controlled values (opts.from, opts.to,
opts.customPrompt), and shell mode could interpret cmd.exe
metacharacters.

Keep shell: true only in probeCommand where args are known-safe
(--version). The original bug (alibaba#453) was specifically about
environment detection failing on Windows, so this targeted fix is
sufficient.
- Replace module-level jest.mock('child_process') with per-test jest.spyOn
  so existing isAvailable / runRaw / testConnection tests continue to
  use the real spawn.
- Add inline comment explaining why shell: true is safe in probeCommand
  (hardcoded --version args, no user input).
- Use explicit expect.objectContaining({ shell: false }) for non-Windows
  assertion instead of expect.not.objectContaining({ shell: true }).
- Remove unused import of spawn from child_process
- Add eslint-disable comment for require() in test (jest.spyOn on non-configurable CommonJS export)
- Replace Function type with explicit (code: number) => void callback type
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 3 issue(s) in this PR.

  • ✅ Successfully posted inline: 3 comment(s)


- name: Create GitHub Release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[security · medium]
Third-party actions should be pinned to a full commit SHA rather than a mutable tag. Tags can be moved or hijacked, posing a supply-chain risk. Consider pinning to the specific commit SHA for softprops/action-gh-release@v2 (e.g., uses: softprops/action-gh-release@<full-sha>). First-party actions/* pinned to major version tags like @v4 / @v2 are acceptable.

# Content-validation guardrails, kept out of ci.yml (which is build/test/lint):
# - blocking: all README*.md translations share the same ## section structure.
# - non-blocking: warn when a docs/en page changes without its zh/ja/ru counterpart.
# - non-blocking: warn when a docs/en page changes without its zh/ja counterpart.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[documentation · medium]
The comments here and on line 43 were updated to say "zh/ja" (removing Russian), but the underlying script scripts/github-actions/check-translation-sync.js was not updated in this PR. It still defines DOCS_LOCALES = ["zh", "ja", "ru"] (line 46) and references "zh/ja/ru" in its own comments (lines 19, 44, 166, 179). This creates a mismatch between what the workflow comments claim and what the check actually does.

Either:

  1. Also update the script to remove "ru" from DOCS_LOCALES and update its comments, or
  2. Revert these comment changes to keep them consistent with the current script behavior.

Comment on lines +35 to +36
// shell: true is safe here because args are hardcoded ['--version'] — no user input.
const proc = spawn(resolveBin(bin), args, { env: getShellEnv(), shell: process.platform === 'win32' });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[maintainability · low]
Minor: The comment states "args are hardcoded ['--version']" to justify shell: true, but args is actually a parameter of probeCommand. While all current callers do pass ['--version'], a future caller could pass user-controlled args, making the security justification stale. Consider either:

  1. Removing the args parameter and hardcoding ['--version'] inside the method (since it's only used for version probing), or
  2. Adjusting the comment to say "all current callers pass hardcoded args" so future developers know to verify safety when adding new call sites.

…y justification

Address OpenCodeReview bot feedback: the previous implementation passed
args as a parameter while claiming they were hardcoded. Now probeCommand
only probes --version, making the shell: true usage unambiguously safe.

Updates call sites in checkEnvironment and test assertions accordingly.

@lizhengfeng101 lizhengfeng101 left a comment

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.

@aalhadxx The core fix (adding shell: process.platform === 'win32' to probeCommand) is correct and well-scoped — no security concerns, good test coverage. However, this PR has significant unrelated changes mixed in that block merging:

1. GitHub Actions version downgrades (breaking)

All workflow files downgrade actions from their current versions on main (e.g. checkout@v7@v4, cache@v6@v4, action-gh-release@v3@v2, attest-build-provenance@v4@v2). These are regressions, likely because your branch is based on a stale commit.

2. package-lock.json added (+10,241 lines)

This project uses yarn. A package-lock.json should not be committed.

3. translation-sync.yml comment changes

Removing "ru" from translation sync comments is unrelated to this fix.

4. yarn.lock changes

Unrelated dependency churn.


Requested action: Please rebase onto the latest main, drop all unrelated changes, and keep only the CliService fix + tests. A clean way to do this:

git fetch origin main
git checkout -b fix/vscode-windows-shell origin/main
git cherry-pick <your-commit-with-CliService-changes>

The actual fix is good — just needs a clean branch. Thanks!

@aalhadxx

Copy link
Copy Markdown
Contributor Author

Closing to replace with a cleaner branch that drops all unrelated lockfile and workflow changes. New PR incoming.

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.

Windows 环境下vs code插件检测误报"未检测到 npm"(spawn 未使用 shell 模式)

2 participants