Skip to content

fix: execute ProxyCommand transport - #293

Merged
inureyes merged 4 commits into
mainfrom
fix/issue-280-proxy-command
Aug 27, 2026
Merged

fix: execute ProxyCommand transport#293
inureyes merged 4 commits into
mainfrom
fix/issue-280-proxy-command

Conversation

@inureyes

@inureyes inureyes commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

  • Execute resolved ProxyCommand values as managed shell child transports instead of silently opening a direct target socket.
  • Match OpenSSH proxy selection semantics across ProxyCommand, ProxyJump, command-line -J, explicit none, and effective %h/%k/%n token identities.
  • Report bounded proxy stderr and exit status as actionable connection errors, and reject unsupported ProxyUseFdpass before spawning a process.

Implementation

  • Add a duplex async transport backed by child stdin/stdout with bounded stderr draining, exit monitoring, deterministic shutdown, and kill-on-drop lifecycle handling.
  • Expand %%, %h, %k, %n, %p, and %r, reject malformed or unsupported tokens, and preserve shell pipes and quoting from trusted SSH configuration.
  • Preserve the first-obtained SSH configuration semantics introduced by the related proxy and host-key changes, with command-line -J taking precedence.
  • Silence only the official but unimplemented SecurityKeyProvider option while retaining diagnostics for genuinely unknown keywords.
  • Preserve raw command exit codes after stdout and stderr and keep draining the SSH channel when the local output receiver closes, fixing integration failures exposed by the real proxy transport.
  • Update user and manual documentation to describe the supported behavior and the explicit ProxyUseFdpass limitation.

Security and quality review

  • Reviewed shell-boundary validation, token expansion, direct-connection avoidance, child cleanup, stderr memory bounds, failure mapping, host-key alias identity, and early receiver-drop behavior; no unresolved CRITICAL or HIGH findings remain.
  • Proxy commands remain an explicitly trusted SSH configuration shell boundary; target-derived tokens retain existing host and username validation, while NUL and newline injection and unsupported expansion tokens are rejected.

Validation

  • cargo fmt --all -- --check
  • cargo test --lib proxy (29 passed)
  • cargo test --lib resolve_effective_jump_hosts (11 passed)
  • cargo test --lib stream_exit (2 passed)
  • cargo test --lib nonzero_stream_completion_preserves_remote_status (1 passed)
  • cargo test --lib closed_output_receiver_is_not_a_command_error (1 passed)
  • cargo test --test ssh_compat_output_test deprecated_alias_is_silent_and_unknown_keyword_uses_log_file -- --exact (1 passed)
  • cargo check --lib --tests
  • cargo clippy --lib --tests -- -D warnings
  • cargo build --bin bssh
  • cargo test --bin bssh (57 passed)
  • TEST_SSH_UNSAFE_PERMISSIONS=1 python3 tests/openssh-regress/run.py --bssh target/debug/bssh --test proxy-connect --jobs 1 --timeout 120 (PASS, 1/1)

Local CI-equivalent note: cargo test --tests -- --skip integration_test passed the library tests (1420 passed, 9 ignored, 13 filtered), the bssh binary tests (57 passed), and the subsequent keygen/server and independent test targets until tests/integration_test.rs; three unchanged localhost SSH-dependent cases failed in the local harness (test_localhost_multiple_file_upload, test_parallel_execution_with_multiple_nodes, and test_download_with_unique_filenames). The PR's exact-head GitHub checks are the authoritative CI verdict for those environment-dependent cases.

Closes #280

Route resolved ProxyCommand values through a managed shell child and use its standard streams as the SSH transport.

Expand OpenSSH proxy tokens, preserve ProxyJump precedence and explicit none, surface bounded stderr and exit status, and reject unsupported descriptor passing before spawn.

Preserve original host aliases through ssh_config resolution, carry raw-stream exit status after stdout and stderr, and keep draining SSH when the local output receiver closes.
@inureyes inureyes added type:bug Something isn't working priority:critical Requires immediate attention status:review Under review labels Aug 27, 2026
Order exact and explicit-disable host blocks before wildcard fallbacks so the connection-manager fixtures match OpenSSH resolution semantics.
Place the exact host before its wildcard fallback in the bssh binary test so it exercises OpenSSH first-obtained behavior.
Keep network KnownHostsCommand values rejected while proving URL-internal equals signs survive line parsing and safe equals-bearing arguments remain accepted.
@inureyes inureyes added status:done Completed and removed status:review Under review labels Aug 27, 2026
@inureyes
inureyes merged commit fa4c857 into main Aug 27, 2026
5 checks passed
@inureyes
inureyes deleted the fix/issue-280-proxy-command branch August 27, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority:critical Requires immediate attention status:done Completed type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(ssh_config): execute ProxyCommand instead of parsing and discarding it

1 participant