Fix #957: persist SSH known-host trust across app restarts#960
Merged
Conversation
useVaultState hydrates knownHosts asynchronously — its init awaits the decryption of hosts, keys, identities and proxyProfiles before reading knownHosts from localStorage. The state is briefly [] at boot even when localStorage has saved entries. The host-key verifier introduced in bce33f3 reads the renderer's knownHosts state at connect time. Any SSH connect that fires inside that hydration window (manual click or auto-restored session) sees an empty trust list, marks every host as unknown, and prompts again. The fix accepted by the user is saved to localStorage, but next restart the same race repeats, giving the impression that fingerprints are never persisted. Use the existing getEffectiveKnownHosts helper at the two sites that feed the SSH connect path (VaultView + TerminalLayerMount). The helper falls back to localStorage while state is still settling, mirroring the same pattern already applied to sync payloads (App.tsx:479). Memoised on the knownHosts state so the prop reference is stable and the TerminalLayer/VaultView React.memo equality checks still hold. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
Fixes the "remembered host fingerprints stop working after restarting netcatty" symptom reported in #957.
Root cause
Commit
bce33f34"Fix SSH known host verification" (shipped in 1.1.3) introduced ahostVerifierin the main process that decides whether a host is trusted by reading theoptions.knownHostsarray passed in from the renderer.The renderer's
knownHostscomes from the React state owned byuseVaultState, and that state is hydrated asynchronously: the init flow in useVaultState.ts:404awaits the decryption of hosts / keys / identities / proxyProfiles before it finally readsknownHostsat line 509. For users with several encrypted keys, the full hydration can easily take a few hundred milliseconds.Until that finishes the React state is still
[], andApp.tsxlines 1999 / 2072 pass that state straight through toVaultView/TerminalLayerMount, which eventually reaches sshBridge.cjs:762createHostVerifier({ knownHosts: options.knownHosts }). If the user clicks connect before hydration completes (manually, or via auto-restored sessions), the verifier sees an empty array, classifies every host as"unknown", and prompts. The user's "accept" is correctly written to localStorage, but next restart the same race fires again — giving the impression that the fingerprint was never saved.Fix
The project already had a
getEffectiveKnownHostshelper. Its docstring spells out the exact situation:The sync-payload code path already used it (App.tsx:479), but the SSH-connect path was missed. This PR wires the same helper into the
knownHostsprop thatVaultViewandTerminalLayerMountreceive.Wrapped in
useMemokeyed on theknownHostsstate so that:React.memoequality checks keep working)Test plan
npx tsc --noEmit— no new errors in changed files (other pre-existing repo-wide TS errors are unrelated to this PR)electron/bridges/hostKeyVerifier.test.cjscomponents/terminal/hostKeyVerification.test.tscomponents/terminal/runtime/createTerminalSessionStarters.test.tscomponents/TerminalLayer.memo.test.tsxdomain/knownHosts.test.tsRelated
🤖 Generated with Claude Code