What happened?
Follow-up to #3395. That PR catches the silent-failure mode where ~/.ssh/id_ed25519.pub on disk doesn't pair with ~/.ssh/id_ed25519 (stale pub copied from another machine, etc.) — but only diagnoses it: the bad pair is filtered out and the user is told to fix it manually.
Real-world report from Slack: user hit SSH key 'id_ed25519' already registered with DigitalOcean followed by 33× Permission denied (publickey) on a hermes launch. With #3395 merged, they'd instead see a "skipped — does not pair" warning and then have to manually run ssh-keygen -y -P "" -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub to recover.
Proposed fix
In discoverSshKeys() (or a new helper), when verifyKeyPair() returns "mismatch":
- Rename the stale
.pub to .pub.spawn-backup-<timestamp> (never destroy user data).
- Write the correct pub — derived from the priv via
ssh-keygen -y -P "" -f <priv> — to <priv>.pub.
- Log:
Repaired ~/.ssh/id_ed25519.pub (stale public key replaced; original saved as .pub.spawn-backup-*).
- Continue with the repaired pair — SSH handshake will now succeed because the pub registered with the cloud provider actually pairs with the local priv.
The .priv is authoritative; any .pub on disk that doesn't derive from it is wrong by definition, so the rewrite is safe. Passphrase-protected keys (verifyKeyPair === "unverifiable") continue to be skipped silently — we can't derive the pub for those without the passphrase.
Acceptance criteria
References
Filed from Slack by SPA
What happened?
Follow-up to #3395. That PR catches the silent-failure mode where
~/.ssh/id_ed25519.pubon disk doesn't pair with~/.ssh/id_ed25519(stale pub copied from another machine, etc.) — but only diagnoses it: the bad pair is filtered out and the user is told to fix it manually.Real-world report from Slack: user hit
SSH key 'id_ed25519' already registered with DigitalOceanfollowed by 33×Permission denied (publickey)on a hermes launch. With #3395 merged, they'd instead see a "skipped — does not pair" warning and then have to manually runssh-keygen -y -P "" -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pubto recover.Proposed fix
In
discoverSshKeys()(or a new helper), whenverifyKeyPair()returns"mismatch":.pubto.pub.spawn-backup-<timestamp>(never destroy user data).ssh-keygen -y -P "" -f <priv>— to<priv>.pub.Repaired ~/.ssh/id_ed25519.pub (stale public key replaced; original saved as .pub.spawn-backup-*).The
.privis authoritative; any.pubon disk that doesn't derive from it is wrong by definition, so the rewrite is safe. Passphrase-protected keys (verifyKeyPair === "unverifiable") continue to be skipped silently — we can't derive the pub for those without the passphrase.Acceptance criteria
.pubis auto-rewritten from the matching.priv.pubis preserved at<priv>.pub.spawn-backup-<timestamp>discoverSshKeys()calls.pub)References
Filed from Slack by SPA