Skip to content

fix(ssh): keep existing hosts' orca CLI control off after the on-by-default flip - #29949

Merged
nwparker merged 3 commits into
mainfrom
nwparker/ssh-remote-cli-control-migration
Oct 17, 2026
Merged

nwparker merged 3 commits into
mainfrom
nwparker/ssh-remote-cli-control-migration

Conversation

@nwparker

@nwparker nwparker commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​124 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​124
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​41 $\color{#cf222e}{\Huge{\mathbf{−}}}$​9 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​32

ELI5

Older Orca versions saved "off" for the SSH host switch "Allow this host's orca CLI to control Orca" by leaving it unset. #29856 made unset mean "on", so anyone who had turned it off would have it switched back on without being asked. This PR turns every host that was already saved before the upgrade off, once. Hosts you add afterwards still start with the switch on.

What Changed

  • Before (on main): a host saved by v1.4.227 or earlier with the switch off has no stored value. isRemoteCliControlAllowed reads that as on, so the host's orca CLI can drive this desktop's Orca browser after the upgrade. Live run on Linux: the desktop browser bridge accepted both the old "off" host and a new host.
  • After: the first time a profile loads, every saved SSH host with no stored value gets an explicit allowRemoteCliControl: false. Explicit true and false values stay as they are. A one-time marker, settings.sshRemoteCliControlExistingHostsMigrated, is saved in the same profile so this runs once. Fresh profiles start with the marker already set. Hosts added afterwards through Settings or either sidebar add-host dialog are still saved with an explicit true, which fix(ssh): turn a host's orca CLI control on by default and stop resetting saved choices #29856 already does.
  • Mechanism: migrateExistingHostsRemoteCliControl (src/main/persistence/leasing-ssh-ptys/ssh-remote-cli-control-migration.ts), called from normalizeLoadedProfileState. That is the only load path for the profile Store. The desktop and the server (orca serve / orcad, which keeps its SSH targets in the same Store) both use it, so both stores are migrated.
  • Help text now reads "On by default for new hosts." in all six locales and the Korean override file.

Why

  • The marker lives in profile settings. Every shipped build spreads unknown settings keys through load and save, so the marker survives a downgrade. If a user downgrades and then upgrades again, the migration does not run a second time over hosts they added on the newer version. It sits in the same profile document as sshTargets, so it is saved together with the pinned values. Adding a new top-level persisted key would also mean new SQLite domain, WSL-move and census work.
  • Mixed versions: an older desktop reads the saved false as off, as before. An older client talking to a migrated server is sent allowRemoteCliControl: false, which it reads as off. Nothing an older client relies on flips to on.
  • What a missing value means after the migration: it stays "on" (isRemoteCliControlAllowed is unchanged). After the migration, a missing value is written by new-build paths that don't pass the switch (SSH config import, managed-server provisioning). Those are hosts added after this release, which the product decision says start on. It can also come from an older build after a downgrade. The server-side rule from fix(ssh): turn a host's orca CLI control on by default and stop resetting saved choices #29856 (a missing value from an older client over RPC is saved as off) is a different boundary: there an older client submitted a form that showed the switch off. That rule still applies, so hosts an older client adds through a new server are stored as off.
  • Alternatives considered:
    • Treat every missing value as off forever. Rejected: hosts imported from SSH config would start off, which contradicts the decision that new hosts are on.
    • A version stamp on each host. Rejected: more fields and nothing gained over a single per-profile marker.

Linked Issue

N/A (user decision on remote CLI control default, follow-up to #29856)

Visual Proof

N/A. This is a load-time data migration plus a one-phrase help-text change; the toggle UI is unchanged.

Testing

  • New src/main/persistence-ssh-remote-cli-control-migration.test.ts drives the real Store with its SQLite profile authority. These fail on main:

    • a saved host with no value loads as false and is saved that way;
    • explicit true and false are kept;
    • the marker is saved;
    • a host added after the migration keeps true across a restart, while the pre-existing host stays false.

    A third test covers the downgrade case: a profile that already has the marker keeps a missing value as is.

  • Focused suites pass: src/main/persistence/loading-store, leasing-ssh-ptys, persistence-settings-update, persistence-ssh-targets-and-pane-keys, ssh-connection-store, desktop-browser-bridge-wiring, ssh-target-management, src/shared/wsl-move, the ssh settings renderer tests and src/renderer/src/i18n. pnpm tc passes. I ran the static-analysis job steps locally and they passed (lint, code-quality plugins, changed-code gate, ratchets, localization, generated catalogs). The one exception is the typecheck:ci bun-compiler wrapper, which fails on this machine with "Script not found check". pnpm tc covers the same projects.

  • Live on omarchy (Linux), isolated /tmp HOME and profile dir:

    1. Seeded a profile shaped like v1.4.227's (one host with the switch off, stored as no value).
    2. Process 1 (upgrade) loaded it, added a new host with the add-host payload, and saved.
    3. Process 2 (restart) reloaded it.

    Both processes ran the real listDesktopBrowserBridgeCandidates. Managed-server fencing and environment resolution were stubbed so both hosts count as connected managed hosts.

    • Result on this branch: old:false,new:true bridge=new, the same after the restart.
    • The same run with main's loader: old:undefined,new:true bridge=old,new.
    • Not exercised live: a real managed orcad deploy with an orca tab create round-trip. The Docker-based e2e can't run on omarchy because there is no Docker.
  • I manually tested these changes locally

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

Review

Codex (gpt-6.1-sol, high) review 1 found one P2: an unchecked type assertion in the new test, which failed the changed-code gate. Fixed. Re-reviews found nothing further.

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

  • Security: this only moves hosts toward off, and only once.
  • Cross-platform: no platform-specific code.
  • SSH and orcad: covered through the shared Store.
  • Mobile: not touched.
  • Backward compatibility: see Why.
  • Performance: one pass over the SSH targets on load.

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)

…on-by-default flip

Builds before the flip saved an explicit off as an absent value, so absent=on
silently turned on hosts the user had turned off. On the first load after this
upgrade, pin every saved host's absent switch to an explicit false and record a
one-shot marker in settings so hosts added later keep the new default.
@coderabbitai

coderabbitai Bot commented Oct 17, 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: a96178a0-6793-4e47-afb9-e2773ade1996
📥 Commits

Reviewing files that changed from the base of the PR and between 9cc5d6b and c59ea92.

📒 Files selected for processing: 14
  • config/scripts/locale-ko-key-overrides.json
  • src/main/persistence-ssh-remote-cli-control-migration.test.ts
  • src/main/persistence/leasing-ssh-ptys/ssh-remote-cli-control-migration.ts
  • src/main/persistence/loading-store/normalize-loaded-global-settings.ts
  • src/main/persistence/loading-store/normalize-loaded-profile-state.ts
  • src/renderer/src/components/settings/SshHostAdvancedFields.tsx
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/shared/default-global-settings.ts
  • src/shared/global-settings-types.ts

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

📝 Walkthrough

Store loading now migrates existing SSH targets whose remote CLI control value is absent, while preserving explicit values. A migration marker prevents the migration from running again. Help text in the component and supported locales clarifies that the default applies to new hosts.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to c59ea

The migration appears ready to merge after normal checks; existing hosts with missing values are saved with CLI control disabled, while new-host defaults remain unchanged.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 7 files. (7 skipped: 7… 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 main change: preserving disabled CLI control for existing SSH hosts after the default changes to enabled.
Description check Passed The description is detailed and covers the user impact, implementation, rationale, alternatives, testing, known limitations, compatibility, and checklist items. It explains that the linked issue is no…
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.
Full details: Description check

Explanation

The description is detailed and covers the user impact, implementation, rationale, alternatives, testing, known limitations, compatibility, and checklist items. It explains that the linked issue is not applicable and documents the untested managed orcad deployment path.

Full details: Docstring Coverage

Explanation

Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 7 files. (7 skipped: 7 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ 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.

@nwparker
nwparker merged commit 7d077ee into main Oct 17, 2026
34 checks passed
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