Skip to content

fix: persist SSH jumphost and tunnel mode in connections.json#793

Merged
datlechin merged 3 commits intomainfrom
fix/connection-persistence
Apr 19, 2026
Merged

fix: persist SSH jumphost and tunnel mode in connections.json#793
datlechin merged 3 commits intomainfrom
fix/connection-persistence

Conversation

@datlechin
Copy link
Copy Markdown
Collaborator

Summary

Closes #790. Partial fix for #780.

Root cause of #790: StoredConnection used flat scalar fields for SSH config (sshHost, sshPort, etc.) but never persisted jumpHosts or sshTunnelMode. Every save/load cycle silently dropped all jump host configuration. First connect worked (in-memory object correct), but reconnecting after app restart failed because connections.json had no jumphost data.

Changes

StoredConnection — sshTunnelModeJson field:

  • Added sshTunnelModeJson: Data? that encodes the full SSHTunnelMode enum (already Codable, includes inline config with jumpHosts, profile with snapshot)
  • On load: prefers JSON blob when present, falls back to legacy flat fields for old connections.json files
  • On save: writes both JSON blob (source of truth) and flat fields (backward compat with older app versions)
  • No migration needed. Old files decode via decodeIfPresent returning nil, legacy flat-field path runs unchanged. Next save writes the blob.

KeychainHelper — loadWithStatus:

  • Added KeychainLoadResult enum: .success(Data), .notFound, .locked, .error(OSStatus)
  • Added loadWithStatus(key:) that distinguishes errSecInteractionNotAllowed (Keychain locked before first unlock after reboot) from errSecItemNotFound
  • Existing load(key:) -> Data? preserved for backward compat

duplicateConnection — pass sshTunnelMode:

  • Now passes sshTunnelMode: connection.sshTunnelMode explicitly instead of relying on auto-derive logic

Export — sshProfileId:

  • Added sshProfileId: String? to ExportableConnection
  • Export includes profile binding; import restores it

Test plan

  • Create MySQL connection with SSH tunnel + jumphost, save, quit app, reopen - jumphost still present
  • Connect with jumphost - succeeds
  • Duplicate connection with jumphost - duplicate has jumphost
  • Old connections.json without sshTunnelModeJson key loads correctly (flat fields used)
  • Export/import connection with SSH profile - profile binding preserved

@datlechin datlechin merged commit 85dab40 into main Apr 19, 2026
2 checks passed
@datlechin datlechin deleted the fix/connection-persistence branch April 19, 2026 11:55
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.

Jumphost lost between 2 connections

1 participant