Skip to content

feat: delegate SSH config aliases to native OpenSSH#346

Closed
itzhang89 wants to merge 2 commits into
bytebase:mainfrom
itzhang89:feat/native-ssh-tunnel
Closed

feat: delegate SSH config aliases to native OpenSSH#346
itzhang89 wants to merge 2 commits into
bytebase:mainfrom
itzhang89:feat/native-ssh-tunnel

Conversation

@itzhang89

Copy link
Copy Markdown

Summary

  • Problem: When ssh_host is a ~/.ssh/config Host alias (e.g. target-with-jump with ProxyJump mybastion), DBHub parses the config and re-implements the jump chain via the ssh2 library. This breaks common setups because:
    • ProxyJump values that are themselves aliases (e.g. mybastion) are treated as literal hostnames
    • All hops share a single username/key, so different credentials per hop cannot work
    • Behavior diverges from the system ssh client
  • Solution: Automatically spawn the system ssh client when ssh_host is a resolvable SSH config alias (no ssh_password, no explicit ssh_proxy_jump). OpenSSH handles ProxyJump, nested aliases, and per-host credentials. The existing ssh2 implementation remains for direct hosts, password auth, and explicit ssh_proxy_jump.
  • Also fixes: Preserve the original --ssh-host alias in single-source CLI mode (instead of replacing it with HostName), and map proxyJump to ssh_proxy_jump.

Example

~/.ssh/config:

Host mybastion
    HostName bastion.example.com
    User ubuntu
    IdentityFile ~/.ssh/id_rsa

Host target-with-jump
    HostName 10.0.0.5
    User admin
    ProxyJump mybastion

dbhub.toml:

[[sources]]
id = "prod_pg"
dsn = "postgres://app_user:secure_password@10.0.1.100:5432/myapp_prod?sslmode=require"
ssh_host = "target-with-jump"

Equivalent to: ssh -N -L 127.0.0.1:<port>:10.0.1.100:5432 target-with-jump

Test plan

  • Unit tests for tunnel mode resolver
  • Unit tests for native SSH arg building
  • ConnectorManager routing tests (native vs ssh2)
  • Existing ssh-tunnel.test.ts still passes
  • Manual: ssh_host = "target-with-jump" with nested ProxyJump mybastion in ~/.ssh/config
  • Manual: direct hostname / ssh_password / ssh_proxy_jump still use ssh2

Made with Cursor

When ssh_host matches a Host alias in ~/.ssh/config (and neither
ssh_password nor ssh_proxy_jump is set), spawn the system ssh client
so ProxyJump chains, nested aliases, and per-hop credentials are
handled by OpenSSH. Direct hosts, password auth, and explicit
ssh_proxy_jump continue to use the ssh2 tunnel.

Co-authored-by: Cursor <cursoragent@cursor.com>
@itzhang89 itzhang89 requested a review from tianzhou as a code owner June 26, 2026 07:51
@tianzhou

Copy link
Copy Markdown
Member

Thanks. For non-trivial changes like this, please open an issue first for discussion

SSHTunnel.establish now receives a single SSHTunnelEstablishRequest
object from ConnectorManager instead of separate config and options args.

Co-authored-by: Cursor <cursoragent@cursor.com>
@itzhang89

Copy link
Copy Markdown
Author

Thanks for the review. Understood — we'll open an issue first to discuss this approach before submitting a PR. Closing for now.

@itzhang89 itzhang89 closed this Jun 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