#20330: Fix SSH tunnel startup on Windows by resolving ssh from PATH
app: macos
size: S
Cluster:
Windows Path and Exec Fixes
# Fix SSH tunnel startup on Windows by resolving ssh from PATH
## Summary
This updates SSH invocation in gateway status SSH helpers to use `ssh` from PATH instead of a hardcoded Unix path. It fixes SSH tunnel/config resolution on platforms where `/usr/bin/ssh` does not exist (notably Windows), and adds regression coverage.
## Problem
- Expected: `openclaw gateway status --ssh ...` should start SSH config/tunnel probing on all supported platforms where SSH is installed.
- Actual: `startSshPortForward` and `resolveSshConfig` spawn `/usr/bin/ssh`, which fails on Windows with `ENOENT`.
- Impact: `gateway status` SSH probing/tunneling is unavailable on Windows environments.
## Reproduction
1. On Windows, run `pnpm openclaw gateway status --ssh user@host`.
2. Observe the SSH path spawn failure (`/usr/bin/ssh` not found).
- Expected result: command resolves SSH via PATH and proceeds with probing/tunnel startup.
- Actual result: command fails to spawn SSH due to hardcoded Unix-only path.
## Issues Found
Severity: high
Confidence: high
Status: fixed
| ID | Severity | Confidence | Area | Summary | Evidence | Status |
| --- | --- | --- | --- | --- | --- | --- |
| PR-20330-BUG-01 | high | high | src/infra | SSH helpers hardcode `/usr/bin/ssh`, breaking Windows SSH probing/tunnel startup | `src/infra/ssh-config.ts`, `src/infra/ssh-tunnel.ts` | fixed |
## Fix Approach
- Replace hardcoded `/usr/bin/ssh` with `ssh` in:
- `src/infra/ssh-tunnel.ts`
- `src/infra/ssh-config.ts`
- Add regression tests:
- Assert `resolveSshConfig` spawns `ssh` (`src/infra/ssh-config.test.ts`)
- Add `src/infra/ssh-tunnel.test.ts` to verify PATH-based SSH spawn for tunnel startup.
## Testing
- `pnpm test src/infra/ssh-config.test.ts src/infra/ssh-tunnel.test.ts` (pass)
- `pnpm build` (pass)
- `pnpm check` (pass)
- `pnpm test` (failed in this environment; unrelated pre-existing test instability around DNS-dependent `example.com` fetch tests such as `src/web/media.test.ts` and `src/agents/tools/web-fetch.*.test.ts`)
## Risk / Notes
- Low risk: this only changes SSH binary resolution to rely on platform PATH.
- macOS/Linux behavior remains compatible when `ssh` is present on PATH.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Replaces hardcoded `/usr/bin/ssh` with PATH-resolved `ssh` in `src/infra/ssh-config.ts` and `src/infra/ssh-tunnel.ts`, fixing SSH tunnel/config resolution on Windows where the Unix path doesn't exist.
- `resolveSshConfig()` and `startSshPortForward()` now spawn `ssh` via PATH lookup instead of `/usr/bin/ssh`
- New test file `src/infra/ssh-tunnel.test.ts` verifies PATH-based spawn for tunnel startup with proper mock TCP server simulation
- Existing `ssh-config.test.ts` extended with regression assertion on the spawned command
- Remaining `/usr/bin/ssh` references in the codebase are appropriately in macOS-only Swift code and documentation — no changes needed there
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — minimal, targeted fix with regression tests and no behavioral change on existing platforms.
- The change is a two-line fix (one per file) replacing a hardcoded Unix path with a PATH-resolved binary name. This is a well-understood, low-risk pattern. Node.js `spawn()` with a bare command name uses the system PATH, which works correctly on all platforms. The fix is backed by new and updated tests. No existing behavior is altered on macOS/Linux where `ssh` is available on PATH.
- No files require special attention.
<sub>Last reviewed commit: 962814f</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#19931: Config: merge PATH env vars and bootstrap Windows bins
by Kemalau · 2026-02-18
80.6%
#10714: fix: handle Windows PATH case-sensitivity in node register invoke
by Yida-Dev · 2026-02-06
78.3%
#10708: fix: handle Windows PATH case-sensitivity in exec environment
by Yida-Dev · 2026-02-06
78.0%
#5496: Fix: Windows path separators stripped in Gateway scheduled task
by giuliozelante · 2026-01-31
77.9%
#18003: feat(infra): Adaptive SSH Environment Wrapper (ARE)
by stakeswky · 2026-02-16
77.5%
#23142: fix(test): Windows CI — use path.join for XDG path assertions in qm...
by ihsanmokhlisse · 2026-02-22
77.2%
#11529: fix(wizard): strip shell-style backslash escapes from workspace paths
by mcaxtr · 2026-02-07
77.1%
#17912: fix: configure git to use HTTPS instead of SSH for GitHub URLs
by MisterGuy420 · 2026-02-16
77.0%
#23480: fix(test): use path.join for cross-platform XDG path assertions in ...
by hydro13 · 2026-02-22
76.4%
#12804: fix(daemon): use wrapper script for pnpm global installs in service...
by odinho · 2026-02-09
76.3%