Repository navigation
feat(ssh): full tunnel parity with dockit — chains, profiles, proxies, TOFU - #174
Merged
Merged
Conversation
…, TOFU
Port the remaining SSH tunnel capabilities from dockit and close the
production-readiness gaps found in the audit:
- deterministic tunnel keys: same SSH hops + same target reuse one
tunnel across connections (no duplicate tunnels per bastion)
- multi-hop chains: transport.rs now builds hop chains via
TunnelManager.start_chain — hop N connects to hop N+1, the last hop
forwards to the database
- SSH profiles: stored in .store.dat ("sshProfiles") with CRUD commands
(list/save/delete) and a profile management dialog; connection dialogs
accept ordered profile hops as the tunnel source
- ~/.ssh/config import: full OpenSSH-subset parser (Host/HostName/Port/
User/IdentityFile, wildcards skipped) + list command + UI import
- system proxy: detect_system_proxy command (hyper-util Matcher +
macOS SCDynamicStore exceptions list) and use_system_proxy on hop
configs — first hop connects through the OS proxy via HTTP CONNECT
- SOCKS5 / HTTP CONNECT local servers (ssh -D equivalent) from dockit:
expose_lan selects the mode, the dual-protocol server dispatches on
the first byte
- host-key TOFU verification (SqlKit-first): check_server_key verifies
against a pinned-fingerprint store; first sight pins, mismatches
reject with a recovery message; verify_host_key still defaults to
lenient
New deps: hyper-util, system-configuration, fast-socks5 (1.0),
percent-encoding. Also: eslint rule antfu/top-level-function disabled
(AGENTS.md prefers const-arrow), architecture doc added
(docs/ssh-tunnel-architecture.md).
Tests: cargo 502 lib tests (94 ssh incl. ported parser suite + new
known_hosts TOFU suite); jest 611; lint + type-check clean.
…leanup Review of #174 surfaced three real gaps: - profile round-trip was lossy: save expanded profileIds into transport_layers, and load reconstructed sshTunnel from those layers — profile identity was dropped, so one edit cycle silently degraded an SSH-profile connection back to inline. ServerConfig now persists the verbatim sshTunnel object and load prefers it (transport layers stay as the execution form) - buildTransportLayers expanded profile hops from a profile store that may not have been fetched yet (fresh session → save → silently empty layers); it is now async and fetches on demand - the TOFU mismatch message told users to "remove the saved host key" with no way to do it — new unpin_ssh_host command restores the recovery path Also cleans port warnings (unused param, irrefutable let, dead helper).
…kfile - unpin_ssh_host command: the TOFU mismatch message told users to remove the saved host key — now there is a recovery path (register included) - ServerConfig persists the frontend's sshTunnel object verbatim (sshTunnel passthrough) — the save/load round-trip no longer loses profile hops (transport layers stay as the execution form) - npm audit fix: newly disclosed dev-chain advisories (handlebars, js-yaml via jest tooling) broke the audit gate repo-wide - connectionStore test: connect awaits the async transport-layer build before reaching the mocked API — flush microtasks instead of racing it
The tests raced on a process-wide OnceLock store path — only the first test's directory won, and parallel scheduling differences (ubuntu vs macos) made later tests see a foreign store and fail. The core now takes the store path as a parameter; tests use isolated files.
…l/oracle) Mirrors DocKit's event-search test stack: an SSH bastion (password + three test keys: ED25519, RSA PEM, ED25519-with-passphrase) with four databases on the internal network only — PostgreSQL 17, MySQL 8.4, SQL Server 2022 and Oracle 23ai Free. Nothing but the bastion's 2223 is exposed to the host (2223 keeps DocKit's 2222 stack runnable alongside). Private test keys are gitignored; authorized_keys and public keys are committed. README documents the stack and the SqlKit connection settings for each database.
CI lint gate fails on yaml/quotes, yaml/block-sequence and yaml/plain-scalar rules; autofix + drop a stray blank line. Parsed before and after with a YAML loader to confirm the compose document is semantically unchanged.
Blankll
added a commit
that referenced
this pull request
Oct 9, 2026
…leanup Review of #174 surfaced three real gaps: - profile round-trip was lossy: save expanded profileIds into transport_layers, and load reconstructed sshTunnel from those layers — profile identity was dropped, so one edit cycle silently degraded an SSH-profile connection back to inline. ServerConfig now persists the verbatim sshTunnel object and load prefers it (transport layers stay as the execution form) - buildTransportLayers expanded profile hops from a profile store that may not have been fetched yet (fresh session → save → silently empty layers); it is now async and fetches on demand - the TOFU mismatch message told users to "remove the saved host key" with no way to do it — new unpin_ssh_host command restores the recovery path Also cleans port warnings (unused param, irrefutable let, dead helper).
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the full SSH-tunnel capability alignment from the cross-repo audit: SqlKit now matches DocKit's implementation surface and closes the production-readiness gaps found on both sides.
Capabilities
tunnel_key()— dockit's strategy)start_chain— hop N connects to hop N+1, last hop forwards to the database; system proxy applies to the first hop only.store.dat, CRUD commands, management dialog, Ultimate-gated management on the connections page~/.ssh/configimportdetect_system_proxy(hyper-util Matcher + macOS SCDynamicStore exceptions) +use_system_proxyHTTP-CONNECT on the first hopssh -Dequivalent;expose_lanselects SOCKS5 vs PortForward; dual-protocol server dispatches on first bytecheck_server_keyverifies against a pinned-fingerprint store — first sight pins, mismatches reject with a recovery messageKnown limitations (documented in docs/ssh-tunnel-architecture.md)
verify_host_keystill defaults to lenient; TOFU engages when enabledssl = disableinside trusted tunnelsTest plan
cargo test --lib— 502 passed (94 ssh: ported parser suite, known_hosts TOFU, chain/transport)jest— 611 passednpm run lint:check+vue-tsc --noEmitclean