Skip to content

feat(connections): connect through a SOCKS5 proxy - #1899

Merged
datlechin merged 1 commit into
mainfrom
feat/socks-proxy
Jul 17, 2026
Merged

feat(connections): connect through a SOCKS5 proxy#1899
datlechin merged 1 commit into
mainfrom
feat/socks-proxy

Conversation

@datlechin

Copy link
Copy Markdown
Member

Closes #1882

What

Adds a per-connection SOCKS5 proxy as a fourth connection method alongside SSH Tunnel, Cloudflare Tunnel, and Cloud SQL Auth Proxy. The connection form gets a SOCKS Proxy pane with Host, Port (default 1080), and an optional Username and Password (Keychain).

How it works

  • New SOCKSProxyManager actor (Core/SOCKS/) built on Network.framework's ProxyConfiguration(socksv5Proxy:) (macOS 14+). An NWListener on a kernel-assigned loopback port relays each driver connection through the proxy; Network.framework performs the SOCKSv5 handshake, including RFC 1929 username/password auth. In-process, no external binary.
  • The database hostname is passed to the proxy unresolved (ATYP=DOMAIN), so names that only resolve behind the proxy work and no DNS query for the DB host leaves the machine. SOCKS5 only; Network.framework has no SOCKS4.
  • A down proxy leaves NWConnection in .waiting forever, so tunnel creation probes the path against an app-owned 15s deadline with withTaskCancellationHandler, keeping the connect cancellable per the CLAUDE.md invariant. Errors name the proxy endpoint.
  • Proxy config rides a fresh NWParameters.PrivacyContext per tunnel, never the process default, so app traffic (Sparkle, AI providers, plugin registry) is never proxied. allowFailover stays false so a broken proxy can never silently fall back to a direct connection.
  • Dispatch is a fourth ConnectionTunnelKind through the existing TunnelManaging / activeTunnelKind / tunneledConnection machinery. Tunnel death means the listener failing; individual relay closes are normal query churn and never trigger reconnect.
  • Capability gating: supportsSOCKSProxy is computed from supportsSSH in PluginMetadataRegistry (both mean "the driver dials a raw TCP host:port"), so HTTP-API drivers are excluded and no plugin changes or ABI bump are needed.
  • Config persists as a JSON blob in StoredConnection only when enabled, is excluded from iCloud sync like the other tunnel modes, and the password lives in the Keychain with delete-on-disable, delete, and duplicate handling.

Adjacent fixes (in touched code, separate CHANGELOG entries)

  • Duplicating a connection dropped its Cloudflare Tunnel and Cloud SQL Auth Proxy settings and never copied their Keychain secrets.
  • The tunnel panes' inline conflict banners were asymmetric (Cloudflare only warned about SSH; SSH had none). All four panes now share TunnelExclusivityBanner and otherEnabledTunnels(excluding:), listing every conflicting method with a disable button.

Tests

  • FakeSOCKS5Server: an in-process RFC 1928/1929 server on a real loopback listener (same trick as FakeCloudflaredRunner).
  • SOCKSProxyManagerTests: byte round-trip through the proxy, credential negotiation, auth reject, unreachable and silent proxy timeouts, cancel-during-connect returns promptly, remote DNS (captured ATYP=DOMAIN bytes), two concurrent relays through one tunnel, close frees the port, recreate replaces the old tunnel.
  • Model Codable round-trips, disabled-mode omission, StoredConnection round-trip, form state round-trip.
  • ConnectionTunnelKindTests extended to the full 2^4 combination matrix.
  • ConnectionFormTunnelExclusivityTests: pairwise and all-enabled conflict matrix plus the disable action.
  • ConnectionStoragePersistenceTests: duplicate carries all three tunnel modes and secrets; delete removes the SOCKS password.

No UI automation: the connect flow needs a reachable SOCKS proxy and database, which is not deterministic in CI. Pane behavior is covered by the view model and coordinator tests above.

Docs

New docs/databases/socks-proxy.mdx (covers the ssh -D use case and the macOS 15 Local Network prompt), overview matrix and pane table updated, page registered in docs.json.

@mintlify

mintlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 17, 2026, 5:20 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@datlechin
datlechin merged commit cf7ce45 into main Jul 17, 2026
3 checks passed
@datlechin
datlechin deleted the feat/socks-proxy branch July 17, 2026 05:20
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.

Support for SOCKS proxy

1 participant