fix(task): resolve bash deterministically on Windows to avoid WSL launcher#9750
Conversation
…ncher When mise spawns `bash -c` for a task on Windows, prefer a real POSIX bash (Git Bash / MSYS2) over the WSL launcher at C:\Windows\System32\bash.exe. The WSL launcher is on PATH first when mise is invoked from PowerShell, and routing into WSL means the spawned task body runs inside a separate Linux user-space where mise-managed Windows tools aren't visible — tasks fail with 'command not found'. Resolution order in resolve_posix_shell_program_path() for bash specifically: 1. MISE_BASH_PATH env var (explicit override). 2. Common Git Bash install locations (Program Files, Program Files (x86), %LOCALAPPDATA%\Programs\Git\bin\bash.exe). 3. The existing which::which_in() PATH search. 4. Final guard: if PATH search returns the WSL launcher (...\Windows\System32\bash.exe or ...\Microsoft\WindowsApps\bash.exe), reject it with a warning and let the spawn fail loudly rather than silently dispatching into WSL. Scope: - Bash only. sh/zsh/fish/ksh/dash keep the existing behavior. - Windows only. Linux/macOS builds are unaffected — the relevant code path was already #[cfg(windows)]. Tests: - Pure helpers (is_bash_basename, git_bash_candidates, is_wsl_launcher_bash) each get unit tests covering case-folding, forward/back slashes, and realistic install paths. - An integration test for resolve_posix_shell_program_path verifies that MISE_BASH_PATH overrides PATH search using a tempdir. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR fixes a Windows-specific bug where
Confidence Score: 5/5Safe to merge. All new logic is Windows-only and bash-specific; Linux/macOS builds are unaffected. The fallback (returning None and letting spawn fail loudly) is strictly better than the previous silent WSL routing. The change is narrowly scoped behind #[cfg(windows)], the new helper functions each have their own unit tests, the refactored program_stem extracts existing logic without behaviour change, and the fallback path was already the safe pre-existing default for all other shells. No files require special attention. src/task/task_executor.rs carries the most new logic but is thoroughly tested. Important Files Changed
Reviews (2): Last reviewed commit: "fix(task): broaden Windows bash candidat..." | Re-trigger Greptile |
There was a problem hiding this comment.
Code Review
This pull request improves bash resolution on Windows by prioritizing real POSIX bash installations over the WSL launcher, which can interfere with Windows-managed tools. It introduces the MISE_BASH_PATH environment variable, checks common Git Bash installation paths, and adds logic to ignore the WSL launcher. Review feedback suggests using which::all_in to find the first valid bash on the PATH and refactoring the program stem extraction logic into a shared helper to avoid duplication.
…cher across PATH Addresses review feedback on PR jdx#9750. - Add MSYS2 standalone install paths (`C:\msys64\usr\bin\bash.exe`, `C:\msys32\usr\bin\bash.exe`) to the candidate list so MSYS2-only users get the auto-fix without having to set MISE_BASH_PATH. The helper is renamed bash_candidates accordingly. - For bash, walk every PATH match via which::which_in_all and pick the first entry that isn't the WSL launcher. This rescues setups where a real POSIX bash is on PATH but appears after C:\Windows\System32. The non-bash path keeps the original which::which_in (single-result) call to avoid changing behavior for sh/zsh/fish/ksh/dash. - Mention MSYS2 in the warning message emitted when only the WSL launcher remains, so users in that situation get pointed at the right escape hatch. - Extract crate::path::program_stem and reuse it from both is_posix_shell_program and is_bash_basename, removing the duplicated basename + .exe-strip parsing. All 16 task::task_executor::tests::* and 12 path::tests::* unit tests pass on Windows MSVC. Manual reverification on PowerShell and Git Bash both resolve bash to C:\Program Files\Git\bin\bash.exe and the bun task runs to completion (1.3.13, MINGW64_NT uname). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
### 🚀 Features - add --inactive option to outdated and upgrade commands for inactive tools by @roele in [#9640](#9640) ### 🐛 Bug Fixes - **(aqua)** resolve bin paths for prefixed v tags by @risu729 in [#9759](#9759) - **(bun)** create bunx alongside bun.exe on Windows install by @JamBalaya56562 in [#9732](#9732) - **(dotnet)** use shared prerelease tool option by @risu729 in [#9720](#9720) - **(node)** use matching node in npm shim by @jdx in [#9749](#9749) - **(task)** resolve bash deterministically on Windows to avoid WSL launcher by @JamBalaya56562 in [#9750](#9750) ### 📚 Documentation - **(secrets)** clarify age strict mode default by @risu729 in [#9737](#9737) - **(tasks)** add bash shebang to conditional-dependencies example by @JamBalaya56562 in [#9747](#9747) - update backend tool option docs by @risu729 in [#9738](#9738) ### 📦 Registry - remove tools with zero users by @jdx in [#9725](#9725) - add scalafmt ([github:scalameta/scalafmt](https://github.com/scalameta/scalafmt)) by @pokir in [#9757](#9757) - remove flarectl by @risu729 in [#9756](#9756) ### Chore - **(release)** strip pre-existing sponsor block before appending canonical one by @jdx in [#9745](#9745) ### New Contributors - @pokir made their first contribution in [#9757](#9757)
|
@JamBalaya56562 this PR breaks bash resolution when a valid bash is first in PATH and also causes a valid See #9932 for extra details |
On Windows an explicitly configured bash path (e.g. a task shell of C:/msys64/usr/bin/bash.exe -c, or windows_default_inline_shell_args) was ignored and silently re-resolved to a different bash such as Git Bash, via the WSL-avoidance logic added in jdx#9750. Honor an explicit path (absolute, or relative with a directory component) verbatim instead of re-resolving it. Also unify how configured shell strings are parsed. A new split_shell_command treats backslashes as literal path characters and only groups double-quoted spans on Windows (Unix keeps shell_words / POSIX semantics), so shell paths with spaces (when quoted) or backslashes survive instead of being mangled. It is used for task shell, hook and watch_files shells, and the *_default_*_shell_args settings. Task::shell() now returns a Result so a malformed explicit shell (e.g. an unbalanced quote) fails loudly instead of silently falling back to the default shell. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
When mise spawns
bash -cfor a task on Windows, prefer a real POSIX bash(Git Bash / MSYS2) over the WSL launcher at
C:\Windows\System32\bash.exe.The WSL launcher is on PATH first when mise is invoked from PowerShell, and
routing into WSL means the spawned task body runs inside a separate Linux
user-space where mise-managed Windows tools aren't visible — tasks fail with
command not foundeven thoughmise installsucceeded.Reproduction
From Git Bash — works
From PowerShell — fails
uname -sinside the spawned bash returnsLinux, confirming the body raninside WSL rather than on Windows. Same
mise.tomlworks or fails basedpurely on which terminal the user ran
misefrom.Why
src/task/task_executor.rs::resolve_posix_shell_program_pathcallswhich::which_in(&task_env_PATH)to makebashan absolute path beforespawning. Under PowerShell,
C:\Windows\System32precedes any Git Bashdirectory on
PATH, so the WSL launcher wins. Under Git Bash,MSYSTEMordering puts
/usr/binfirst, so the real bash wins. The previous code hadno Git Bash preference and no WSL-launcher rejection.
Resolution order
The
bash-specific path insideresolve_posix_shell_program_path:MISE_BASH_PATHenv var — explicit user override (task env, then process env).C:\Program Files\Git\bin\bash.exeC:\Program Files (x86)\Git\bin\bash.exe%LOCALAPPDATA%\Programs\Git\bin\bash.exewhich::which_in(&task_env_PATH)search.(
...\Windows\System32\bash.exeor...\Microsoft\WindowsApps\bash.exe),reject it with a warning and let the spawn fail loudly rather than silently
routing into WSL.
Scope
sh/zsh/fish/ksh/dashkeep the existing behavior.#[cfg(windows)]; Linuxand macOS builds are unaffected — both
resolve_posix_shell_program_pathand
maybe_convert_env_for_msys_shellsit behind#[cfg(windows)]gates.Test plan
cargo fmt --checkcleanUnit tests added (Windows-gated):
is_bash_basename— acceptsbash/bash.exe/BASH.EXE/ absolute paths; rejectssh/zsh.exe/fish/dash/cmd.exe/bashfoois_wsl_launcher_bash— detectsC:\Windows\System32\bash.exe(any drive, any case) and...\Microsoft\WindowsApps\bash.exe(forward or back slash); acceptsC:\Program Files\Git\bin\bash.exe,C:\Program Files\Git\usr\bin\bash.exe,C:\msys64\usr\bin\bash.exe, scoop / per-user installsgit_bash_candidates— emits Program Files paths; appends aLOCALAPPDATA\Programs\Git\bin\bash.execandidate whenLOCALAPPDATAis in the task envresolve_posix_shell_program_path—MISE_BASH_PATHoverride is honored via tempdir; non-POSIX shells skip the path; Unix-form PATH skips the pathAll 15 tests in
task::task_executor::tests::*pass on Windows MSVC buildManual verification on Windows 11 with locally built mise:
command not foundWSL Linux build of mise was not exercised because the relevant code is
#[cfg(windows)]and is not compiled on Linux targets.Adjacent / related
shell = "bash -c"flavor of the same family)🤖 Generated with Claude Code