Skip to content

fix(windows): reject WSL bash.exe in findGitBashPath detection - #1329

Merged
Simple6K merged 1 commit into
mainfrom
fix/windows-wsl-bash-reject
Aug 2, 2026
Merged

fix(windows): reject WSL bash.exe in findGitBashPath detection#1329
Simple6K merged 1 commit into
mainfrom
fix/windows-wsl-bash-reject

Conversation

@Simple6K

@Simple6K Simple6K commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

问题

Windows 启用 WSL 时,where.exe bash 返回 C:\Windows\System32\bash.exe(WSL 启动器)和 %LOCALAPPDATA%\Microsoft\WindowsApps\bash.exe(WSL App Execution Alias),位置常在 Git for Windows 的 bash 之前。原 findExecutableWithDeps 直接返回首个非 cwd 结果,CCB 因此把 WSL 启动器误认为 Git Bash,污染 process.env.SHELLCLAUDE_CODE_GIT_BASH_PATH 整个会话,所有 hook / BashTool 调用都会拉起 wsl.exe 弹窗。

修改

  • src/utils/windowsPaths.ts — 在 findExecutableWithDeps 内、当 executable='bash' 时,过滤 System32 与 WindowsApps 的 bash.exe 候选。continue 到下一个 where.exe 命中,让 PATH 后续的合法 Git Bash 仍能胜出。下游消费者(setShellIfWindows env 传播、hooks.ts spawn 点、Shell.ts SHELL 分支)通过 env 缓存自动受益。
  • src/utils/Shell.tsfindSuitableShell 启动入口:检测到 WSL bash 但无 Git for Windows 且未设 CLAUDE_CODE_GIT_BASH_PATH override 时,输出一次性 warning。
  • src/utils/doctorDiagnostic.ts — 相同条件的 claude doctor 持久诊断项,方便用户随时复查。

Test plan

  • 新增 3 个单元测试覆盖该过滤器(src/utils/__tests__/windowsPaths.test.ts):
    • 拒绝 WSL System32 bash → null
    • 拒绝 WSL WindowsApps bash → null
    • 跳过 WSL bash,fall through 到下一个 where.exe 命中(Git Bash later in PATH)
  • bun run precheck 通过:typecheck 0 errors / biome 0 fixes / 5987 pass / 0 fail / 10 skip
  • Windows 实机:启用 WSL + 仅装 Git for Windows 的机器上,确认 hook 和 BashTool 不再触发 wsl.exe 弹窗
  • Windows 实机:仅启用 WSL(无 Git for Windows)时,claude doctor 输出对应 warning 项

🤖 Generated with Claude Code Best

Summary by CodeRabbit

  • Bug Fixes
    • Improved Windows shell detection to avoid selecting WSL Bash when Git Bash is unavailable.
    • Continued searching for valid Git Bash installations when unsuitable Bash launchers are found.
    • Added clearer diagnostics and remediation guidance for missing Git Bash configurations.
    • Prevented shell-detection failures from interrupting normal operation.

Windows 启用 WSL 时,`where.exe bash` 返回 C:\Windows\System32\bash.exe(WSL 启动器)和 %LOCALAPPDATA%\Microsoft\WindowsApps\bash.exe(WSL App Execution Alias),位置常在 Git for Windows 的 bash 之前。原 findExecutableWithDeps 直接返回首个非 cwd 结果,CCB 因此把 WSL 启动器误认为 Git Bash,污染 process.env.SHELL 与 CLAUDE_CODE_GIT_BASH_PATH 整个会话,所有 hook / BashTool 调用都会拉起 wsl.exe 弹窗。

在 findExecutableWithDeps 内、当 executable='bash' 时,过滤 System32 与 WindowsApps 的 bash.exe 候选。continue 到下一个 where.exe 命中,让 PATH 后续的合法 Git Bash 仍能胜出。下游消费者(setShellIfWindows env 传播、hooks.ts spawn 点、Shell.ts SHELL 分支)通过 env 缓存自动受益。

同时添加用户可见的提示:
- Shell.ts findSuitableShell:检测到 WSL bash 但无 Git for Windows 且未设 CLAUDE_CODE_GIT_BASH_PATH override 时,启动一次性 warning。
- doctorDiagnostic.ts:相同条件的 `claude doctor` 持久诊断项,方便用户随时复查。

3 个新单元测试覆盖该过滤器:
- 拒绝 WSL System32 bash → null
- 拒绝 WSL WindowsApps bash → null
- 跳过 WSL bash,fall through 到下一个 where.exe 命中

Co-Authored-By: glm-5.2[1m] <zai-org@claude-code-best.win>
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Windows Bash discovery now rejects WSL launcher aliases under System32 and WindowsApps. Runtime warnings and diagnostics identify missing Git Bash and provide installation or CLAUDE_CODE_GIT_BASH_PATH alternatives.

Changes

Windows Bash handling

Layer / File(s) Summary
Filter WSL Bash launchers
src/utils/windowsPaths.ts, src/utils/__tests__/windowsPaths.test.ts
findExecutableWithDeps skips WSL launcher aliases and continues searching for a valid Git Bash path. Tests cover rejected aliases, missing Git Bash, and later valid results.
Warn about missing Git Bash
src/utils/Shell.ts, src/utils/doctorDiagnostic.ts
Windows checks detect WSL Bash without Git Bash, emit the runtime warning once, and provide Git Bash installation or CLAUDE_CODE_GIT_BASH_PATH setup options.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: claude-code-best

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: rejecting WSL bash.exe candidates during Windows Git Bash detection.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/windows-wsl-bash-reject

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/Shell.ts`:
- Around line 80-103: Replace the PATH-only Git Bash availability logic in
src/utils/Shell.ts lines 80-103 with the shared resolver from
src/utils/windowsPaths.ts, while preserving the WSL launcher check; use the
resolver result so valid overrides and Git for Windows found in standard
locations suppress the warning, but invalid overrides do not. Apply the same
resolver-based decision in src/utils/doctorDiagnostic.ts lines 369-386 so the
diagnostic does not warn when a valid override or discoverable Git Bash exists.
Add regression coverage for both a valid CLAUDE_CODE_GIT_BASH_PATH override and
Git for Windows unavailable from where.exe bash.
- Around line 85-88: Update the where.exe lookup inside findSuitableShell() to
use asynchronous Bun subprocess execution instead of execFileSync, while
preserving ignored failures and the existing PATH-detection behavior. Apply a
bounded timeout to the subprocess so shell discovery cannot hang.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d157026-299e-46c4-8f5a-3fcf94bf2c0c

📥 Commits

Reviewing files that changed from the base of the PR and between 987e550 and b745752.

📒 Files selected for processing (4)
  • src/utils/Shell.ts
  • src/utils/__tests__/windowsPaths.test.ts
  • src/utils/doctorDiagnostic.ts
  • src/utils/windowsPaths.ts

Comment thread src/utils/Shell.ts
Comment on lines +80 to +103
getPlatform() === 'windows' &&
!process.env.CLAUDE_CODE_GIT_BASH_PATH &&
!process.env.CLAUDE_CODE_GIT_BASH_PATH_WARNED
) {
try {
const whereResult = execFileSync('where.exe', ['bash'], {
stdio: ['ignore', 'pipe', 'ignore'],
encoding: 'utf8',
})
const lines = whereResult
.split(/\r?\n/)
.map(l => l.trim().toLowerCase())
.filter(Boolean)
const hasWslBash = lines.some(l =>
/(?:system32|windowsapps)\\bash\.exe$/.test(l),
)
const hasGitBash = lines.some(l => /\\git\\.*bash\.exe$/.test(l))
if (hasWslBash && !hasGitBash) {
process.env.CLAUDE_CODE_GIT_BASH_PATH_WARNED = '1'
console.warn(
'[CCB] Detected WSL bash on PATH without Git for Windows. ' +
'Hooks and BashTool will not work correctly. ' +
'Install Git for Windows (https://git-scm.com/download/windows) ' +
'or set CLAUDE_CODE_GIT_BASH_PATH to your bash.exe.',

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the Git Bash resolver for the availability check.

where.exe bash only reports Bash executables on PATH. It does not determine whether a usable Git Bash exists. The resolver in src/utils/windowsPaths.ts also validates CLAUDE_CODE_GIT_BASH_PATH, derives Bash from Git, and searches standard locations.

  • src/utils/Shell.ts#L80-L103: Keep the WSL launcher check, but use the resolver result to determine whether a usable Git Bash or valid override exists. The current nonempty override check suppresses warnings for invalid paths.
  • src/utils/doctorDiagnostic.ts#L369-L386: Use the same resolver result. The current diagnostic warns even when a valid CLAUDE_CODE_GIT_BASH_PATH override exists.

Add regression coverage for a valid override and for Git for Windows that is discoverable without appearing in where.exe bash. The PR objective requires Git Bash-or-override detection.

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFileSync, spawn } from 'child_process'
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

📍 Affects 2 files
  • src/utils/Shell.ts#L80-L103 (this comment)
  • src/utils/doctorDiagnostic.ts#L369-L386
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/Shell.ts` around lines 80 - 103, Replace the PATH-only Git Bash
availability logic in src/utils/Shell.ts lines 80-103 with the shared resolver
from src/utils/windowsPaths.ts, while preserving the WSL launcher check; use the
resolver result so valid overrides and Git for Windows found in standard
locations suppress the warning, but invalid overrides do not. Apply the same
resolver-based decision in src/utils/doctorDiagnostic.ts lines 369-386 so the
diagnostic does not warn when a valid override or discoverable Git Bash exists.
Add regression coverage for both a valid CLAUDE_CODE_GIT_BASH_PATH override and
Git for Windows unavailable from where.exe bash.

Comment thread src/utils/Shell.ts
Comment on lines +85 to +88
const whereResult = execFileSync('where.exe', ['bash'], {
stdio: ['ignore', 'pipe', 'ignore'],
encoding: 'utf8',
})

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate Shell.ts =="
fd -a 'Shell\.ts$' . || true

echo "== git diff stat/name-status =="
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat 2>/dev/null || true
git diff --name-only HEAD~1..HEAD 2>/dev/null || git diff --name-only 2>/dev/null || true

echo "== inspect Shell.ts outline/sections =="
if [ -f src/utils/Shell.ts ]; then
  wc -l src/utils/Shell.ts
  sed -n '1,160p' src/utils/Shell.ts
fi

echo "== search execFileSync/spawn usage =="
rg -n "execFileSync|execFileSync|spawn\(|Bun\.spawn|where\.exe|bash" src package.json bun.lock 2>/dev/null || true

Repository: claude-code-best/claude-code

Length of output: 50385


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== inspect Shell.ts outline/sections =="
if [ -f src/utils/Shell.ts ]; then
  wc -l src/utils/Shell.ts
  sed -n '1,160p' src/utils/Shell.ts
fi

echo "== search process execution and Shell findSuitableShell callers =="
rg -n "findSuitableShell|execFileSync|execFileSync|spawn\(|Bun\.spawn|where\.exe|bash" src package.json bun.lock 2>/dev/null || true

echo "== deterministic source shape check using Python =="
python3 - <<'PY'
from pathlib import Path
p = Path('src/utils/Shell.ts')
if not p.exists():
    raise SystemExit('src/utils/Shell.ts not found')
text = p.read_text()
checks = {
    'has_async_findSuitableShell': 'async function findSuitableShell' in text or 'findSuitableShell(' in text and 'async' in text[:text.find('findSuitableShell(') + 200],
    'has_execFileSync': 'execFiles ync' in text or 'execFileSync' in text,
    'has_where_exe': 'where.exe' in text,
    'has_Bun_spawn_in_Shell': 'Bun.spawn' in text,
}
print(checks)
# Print exact lines with symbols.
for i, line in enumerate(text.splitlines(), 1):
    if any(s in line for s in ['findSuitableShell', 'execFileSync', 'where.exe', 'Bun.spawn', 'timeout']):
        print(f'{i}: {line}')
PY

Repository: claude-code-best/claude-code

Length of output: 50387


Use asynchronous Bun process execution for the PATH lookup.

findSuitableShell() is async, so execFileSync('where.exe', ['bash']) blocks shell discovery until where.exe returns and can hang without a timeout. Replace this lookup with Bun subprocess execution, keep failures ignored, and add a bounded timeout for the lookup.

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] Importing child_process exposes a command-execution surface; ensure any command/argument built from input is validated, and prefer execFile/spawn with an argument array over exec.
Context: import { execFileSync, spawn } from 'child_process'
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(detect-child-process-typescript)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/Shell.ts` around lines 85 - 88, Update the where.exe lookup inside
findSuitableShell() to use asynchronous Bun subprocess execution instead of
execFileSync, while preserving ignored failures and the existing PATH-detection
behavior. Apply a bounded timeout to the subprocess so shell discovery cannot
hang.

Source: Coding guidelines

@Simple6K
Simple6K merged commit 24e4f3d into main Aug 2, 2026
7 checks passed
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.

1 participant