Skip to content

fix(ssh): Cancel on an SSH password prompt no longer brings it straight back - #28402

Merged
OrcaWin merged 5 commits into
mainfrom
fix/ssh-credential-cancel-loop
Oct 13, 2026
Merged

OrcaWin merged 5 commits into
mainfrom
fix/ssh-credential-cancel-loop

Conversation

@OrcaWin

@OrcaWin OrcaWin commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 7 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​324 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​321
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​109 $\color{#cf222e}{\Huge{\mathbf{−}}}$​11 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​98

ELI5

If Orca asks for an SSH password or key passphrase and you press Cancel, Orca now takes that as your answer. It stops asking for that host until you click Reconnect (or Connect / Test) yourself.

What Changed

Before: on a host that needs a password or passphrase, pressing Cancel brought the dialog straight back, within a few seconds, over and over. This happened even when no workspace on that host was open. The dialog is modal, so a user who did not remember the password could not use Orca at all.

After: Cancel ends that sign-in. The host shows as needing sign-in ("SSH authentication failed") in its status. Nothing automatic opens the dialog again: background status checks, the managed-server tunnel, terminal and server censuses, reconnect after sleep, startup restore, pane mounts and automations all stay quiet. The user can click Reconnect on the host, the terminal overlay, the status bar or Settings, and the prompt then appears again as normal. A dialog left unanswered until its 2-minute timeout counts as Cancel.

Mechanism: since every SSH host runs a managed Orca server, the app reaches the server through an SSH tunnel. Main-process work dials that tunnel through the shared SSH connection manager. This includes the host-status checker, which retries every 3–60 s, every runtime call, the census and maintenance. Each dial that hit a password or passphrase opened the credential dialog, and a Cancel only failed that one attempt. The next retry prompted again.

There is now one record of "the user cancelled sign-in for host X" (src/main/ssh/ssh-credential-decline.ts):

  • It is written only when the user presses Cancel or the prompt times out. A connection that tears down its own prompt does not write it.
  • The connection manager refuses new automatic dials for that host as an auth failure, without touching the network. So the status checker and tunnel callers report the host as unverifiable instead of retrying the prompt.
  • The credential callback answers "cancelled" for any prompt from an already-open connection's own reconnect.
  • ssh:needsPassphrasePrompt reports true, so panes and automations that probe first skip the dial.
  • Only an explicit connect clears it: ssh:connect from a user action, the ssh.connect RPC, or Test Connection. The renderer's automatic callers (startup restore, pane mount, automation dispatch) now pass automatic: true, so they cannot clear it.

Why

The bug is in "who may open a credential prompt", not in any one retry loop, and there are many automatic callers. Adding a backoff or a check to each one (status owner, tunnel, census, resume, restore) would leave the next new caller free to bring the loop back. A single per-host record, enforced where every dial and every prompt passes, covers all current and future background paths. Keeping the gate at the prompt as well means a key that starts working (for example after ssh-add) is still accepted by an in-flight reconnect. The record lives in memory, so after a restart the host gets one prompt, not a loop.

Regression source: #24863 (Phase 3), which made every SSH host a managed server reached through a tunnel that background work dials. Before that, background work never dialed a host. #27214 also stopped saving lastRequiredPassphrase, which startup restore used to delay password hosts.

Linked Issue

STA-10477

Visual Proof

N/A — no visual change. The existing dialog and host status are reused. The change is that the dialog no longer reappears after Cancel.

Testing

  • New failing-first tests:

    • src/main/ipc/ssh-credential-cancel.test.ts: after Cancel, there is no new prompt from automatic requests; panes and automations see "needs sign-in"; startup restore's automatic connect keeps the decline; an explicit Reconnect and Test Connection prompt again; other hosts are unaffected.
    • src/main/ssh/ssh-connection-manager.test.ts: automatic dials are refused as an auth error with no connection opened; a live connection is still reused; dialing works again after an explicit sign-in.
    • src/main/ipc/ssh-passphrase.test.ts: Cancel and timeout record a decline; answered, aborted and windowless requests do not.
    • src/renderer/src/startup/startup-ssh-connection-restore.test.ts: restore dials as automatic.
  • pnpm tc, vitest src/main/ipc plus the affected renderer suites, oxlint, pnpm run check:code-quality:changed and pnpm lint all pass.

  • Not manually tested against a real password host on this machine: no Electron or Docker runs here.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH and remote: only the desktop's own credential prompt is gated. The ssh.connect RPC that remote, mobile and web clients use counts as explicit, so their user-driven connects still prompt on the host. There is no wire change.
  • Cross-platform: no platform-specific code.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6bb43b9d-385b-4ace-811d-3e19ca13dd59
📥 Commits

Reviewing files that changed from the base of the PR and between c745051 and 6a76c67.

📒 Files selected for processing: 20
  • src/main/ipc/runtime-environment-connectivity-handlers.ts
  • src/main/ipc/ssh-connect-flow.ts
  • src/main/ipc/ssh-connection-handlers.ts
  • src/main/ipc/ssh-connection-state-callbacks.ts
  • src/main/ipc/ssh-credential-cancel.test.ts
  • src/main/ipc/ssh-passphrase.test.ts
  • src/main/ipc/ssh-passphrase.ts
  • src/main/ipc/ssh.ts
  • src/main/ssh/ssh-connection-manager.test.ts
  • src/main/ssh/ssh-connection-manager.ts
  • src/main/ssh/ssh-credential-decline.test.ts
  • src/main/ssh/ssh-credential-decline.ts
  • src/preload/api/ssh-api.ts
  • src/preload/api/ssh-bridge.ts
  • src/renderer/src/components/terminal-pane/pty-connection-unserved-ssh-pane.test.ts
  • src/renderer/src/components/terminal-pane/pty-connection/unserved-ssh-pane-connect.ts
  • src/renderer/src/hooks/automation-dispatch-workspace.ts
  • src/renderer/src/hooks/useAutomationDispatchEvents.test.ts
  • src/renderer/src/startup/startup-ssh-connection-restore.test.ts
  • src/renderer/src/startup/startup-ssh-connection-restore.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.

📝 Walkthrough

The change adds target-keyed SSH credential-decline state. Credential timeouts and null responses record a decline, while aborts and requests without a window do not. Connection flows check or clear this state, and the connection manager rejects new attempts for declined targets. The SSH connect API now accepts an optional automatic flag, which startup restoration, automation dispatch, and unserved SSH pane connections set to true.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 6a76c

Cancelling an SSH sign-in prompt now stops background activity from reopening it, and an explicit reconnect still works. No outstanding defects were found.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 40.91% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 22 functions across 20 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the primary SSH credential-cancellation fix.
Description check Passed The description is detailed and covers the user impact, mechanism, rationale, testing, compatibility, and checklist. The linked issue is identified as STA-10477 but is not formatted as an actual issue…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

m4air and others added 5 commits October 13, 2026 14:59
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…ts SSH host

Co-Authored-By: Claude <noreply@anthropic.com>
…ful sign-in lifts the decline

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@OrcaWin
OrcaWin force-pushed the fix/ssh-credential-cancel-loop branch from 6a76c67 to 647b5ce Compare October 13, 2026 22:01
@OrcaWin
OrcaWin merged commit ed18c2c into main Oct 13, 2026
45 checks passed
registered2nd pushed a commit to registered2nd/orca that referenced this pull request Oct 14, 2026
…ht back (stablyai#28402)

* fix(ssh): a cancelled sign-in stays cancelled until the user reconnects

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ssh): drive the credential cancel through the IPC harness

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): an explicit server connect lifts the cancelled sign-in of its SSH host

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ssh): the cancelled attempt may still offer a password; a successful sign-in lifts the decline

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ssh): build the managed-server link without the newer kind field

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: m4air <m4air@Mac.localdomain>
Co-authored-by: Claude <noreply@anthropic.com>
(cherry picked from commit ed18c2c)

Release pick note: runtime-environment-connectivity-handlers.ts conflicted with main's WSL host series (stablyai#27874/stablyai#27940/stablyai#27933), which is not on this release. Kept only this PR's two lines there (the clearSshCredentialDeclinedForEnvironment import and call).
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.

1 participant