Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: robust SSH ping parsing on Windows#39

Merged
bvisible merged 2 commits into
bvisible:mainfrom
username77:fix/windows-ping-healthcheck
May 26, 2026
Merged

fix: robust SSH ping parsing on Windows#39
bvisible merged 2 commits into
bvisible:mainfrom
username77:fix/windows-ping-healthcheck

Conversation

@username77

Copy link
Copy Markdown
Contributor

Summary

Normalize ping health-check output to avoid false dead connections on Windows/OpenSSH shells.

Problem

ssh_connection_status could report a live connection as Dead when echo "ping" returns quoted/escaped output (for example "ping") instead of exact ping.

Fix

  • In src/ssh-manager.js ping():
    • normalize stdout (CRLF, quotes, backslashes)
    • case-normalize
    • validate via includes('ping') rather than strict equality

Validation

  • Local test suite passes (npm test)
  • Reproduced Windows output variant and confirmed health-check now returns true.

@username77

Copy link
Copy Markdown
Contributor Author

Repro detail (Windows/OpenSSH): the health-check command can return quoted output, e.g. RAW_STDOUT="\"ping\"\r\n" instead of plain ping. With strict equality this marks an alive connection as Dead; with normalization + includes('ping') it reports correctly as active.

@bvisible

Copy link
Copy Markdown
Owner

Thanks for catching this — the bug is real. cmd.exe echoes the surrounding quotes literally, so echo "ping" returns "ping" and the old strict === 'ping' check marked a perfectly healthy Windows/OpenSSH session as Dead, which then tears down and rebuilds a pooled connection for nothing.

Before merging I'd like to fold in two refinements. Here's the why for each:

1. Fix the root cause, not only the symptom: echo ping (no quotes)

Normalizing the output is good defense-in-depth, but the quotes only appear because the command itself wraps the token in quotes and cmd.exe doesn't strip them. echo ping (unquoted) emits a bare ping consistently across bash, cmd.exe and PowerShell, so we remove the variance at the source and the normalizer becomes a safety net rather than the primary mechanism.

2. Extract the parsing into a pure, unit-tested function

The PR description says npm test passes — but the existing suite never exercised ping() at all, so it couldn't have caught this regression and can't protect against a future one. I pulled the logic into an exported isPingAlive(stdout) so it's testable without a live SSH connection, and added tests/test-ssh-ping.js (wired into npm test) covering the quoted/escaped/CRLF/case variants — including your exact repro "\"ping\"\r\n".

async ping() {
  try {
    // Use `echo ping` WITHOUT quotes: cmd.exe echoes surrounding quotes
    // literally (outputs `"ping"`), which broke the strict equality check and
    // marked healthy Windows/OpenSSH sessions as dead. Output handling lives
    // in isPingAlive() so it can be unit-tested without a live connection.
    const result = await this.execCommand('echo ping', { timeout: 5000 });
    return isPingAlive(result.stdout);
  } catch (error) {
    return false;
  }
}

// Validate liveness-probe output across shells (bash, cmd.exe, PowerShell).
// Normalize CRLF, stray quotes/backslashes and case before matching so quoted
// or escaped variants (e.g. `"ping"`, `\"ping\"\r\n`) still count as alive.
// `includes` (not strict `===`) is deliberate: a liveness probe should err
// toward "alive" — a false positive merely lets the next real command
// reconnect, whereas a false negative needlessly tears down a healthy pooled
// connection.
export function isPingAlive(stdout) {
  const normalized = (stdout || '')
    .replace(/[\r\n]+/g, ' ')
    .replace(/["'`\\]/g, '')
    .trim()
    .toLowerCase();
  return normalized.includes('ping');
}

On keeping your includes('ping') (rather than tightening it back to ===): that's intentional and I kept it. For a liveness probe, erring toward "alive" is the correct bias — a false positive just means the next real command reconnects, whereas a false negative needlessly drops a healthy connection. Guarding the stdout || '' also makes it null/undefined-safe.

Please test on a real Windows host 🙏

I could only validate the JS logic on macOS, and that's exactly the limitation here: Unix shells strip the quotes, so on Linux/macOS both echo "ping" and echo ping print ping — the bug is not reproducible off Windows. So:

  • node tests/test-ssh-ping.js and npm test pass here (14/14 for the new suite), and a stubbed "\"ping\"\r\n" confirms ping() now returns true.
  • Could you confirm against a real Windows/OpenSSH target — ideally both cmd.exe and PowerShell default shells — that ssh_connection_status reports the session as active with the echo ping variant? That's the one path I can't exercise from here.

Happy to push these changes onto the branch if you'd prefer — just let me know.

@username77

Copy link
Copy Markdown
Contributor Author

@bvisible Thanks — I implemented your refinements on this PR branch and tested against a real Windows/OpenSSH host (toliman).

What I changed:

  • ping() now uses echo ping (no quotes)
  • extracted/exported isPingAlive(stdout)
  • added tests/test-ssh-ping.js
  • wired it into npm test as test:ping

Validation done:

  • npm test passes with the new ping suite
  • Windows real-host check via this MCP setup: ssh_connection_status remains ✅ Active after reconnect and repeated status checks (no false Dead regression)
  • I also reproduced the quoted-output behavior ("ping" variants) and confirmed isPingAlive() handles it correctly.

Pushed commit: ac2d88e.

@bvisible bvisible merged commit 94257cb into bvisible:main May 26, 2026
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.

2 participants