Skip to content

Keep workspace file drops on the terminal's host - #26830

Merged
OrcaWin merged 1 commit into
mainfrom
nwparker/managed-terminal-file-drop-owner
Oct 9, 2026
Merged

OrcaWin merged 1 commit into
mainfrom
nwparker/managed-terminal-file-drop-owner

Conversation

@nwparker

@nwparker nwparker commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 9 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​294 $\color{#cf222e}{\Huge{\mathbf{−}}}$​61 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​233
Prod 12 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​93 $\color{#cf222e}{\Huge{\mathbf{−}}}$​28 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​65

ELI5

Dragging a remote file into a desktop terminal could paste a path naming an unrelated desktop file. The terminal now refuses files from another or unknown host with “Drop files from the same host as this terminal.” Same-host drops still work across workspaces.

What Changed

The internal drop handler compares the existing source metadata with the receiving terminal’s transport before writing any path. A managed server’s local terminal belongs to that server; an optional server ID also distinguishes identical SSH target IDs owned by different servers. Explorer selections retain the cached rows’ owner, and Source Control and combined-diff drags require known workspace ownership. Existing stale-pane checks, path limits, and shell escaping remain in use. The refusal is translated in all six locales.

Why

An absolute path identifies a file only on its owning host. Checking the receiving transport and existing drag metadata prevents the active workspace from assigning another host’s file to the terminal. Copying files between hosts would require a separate transfer flow.

Linked Issue

Internal contribution found during SSH testing; no separate issue. The former parent #26668 has merged. This PR targets main directly; the template asks maintainers to avoid needless issues.

Visual Proof

Before: the managed Files drag names its remote owner, but the desktop terminal reads DESKTOP_BROWSER_DROP_OWNER. An independent managed-host read returns REMOTE_BROWSER_DROP_OWNER.

Before

After, freshly built published head b0b0ce387c777efa29ac49a71120f377140bc56f: the drop shows the refusal and inserts no foreign path. Desktop-to-desktop and managed-to-managed controls still read their own contents.

After

Testing

  • I manually tested these changes locally
  • Automated unit/component tests added or updated

Fresh qualification of published head b0b0ce387c777efa29ac49a71120f377140bc56f:

  • 201 tests across 19 files pass: ownership rejection, nested SSH namespaces, cached selections, same-host acceptance, stale targets and asynchronous writes, folder/worktree ownership, terminal header handling, and shell escaping.
  • Full typecheck, oxlint, and the changed-code quality gate pass. Fresh Electron build in E2E mode passes.
  • Three actual drop journeys pass, zero skips, in 50.6 seconds. Hidden macOS Electron, disposable Linux Docker SSH host, actual Files-row/terminal-surface HTML5 events, real shell keyboard input, and independent host reads. Fully painted refusal screenshot inspected. The prior proof spec was run locally against this published product build; it is absent from the current PR diff.
  • Matching rebuilt parent fails on wrong desktop contents; ownership regressions fail on the parent.
  • Before merge, CI passed all five Node shards, repository guards, static analysis/typecheck, relay integration, macOS/Windows packaging and E2E build; the Docker lane was still running at the last check.

Native Windows and native OS dragging were not exercised locally.

Review

P1 / Medium merge risk. Self-review checked rejection before writes, nested SSH server identity, unknown owners, same-host acceptance, stale panes and partial writes, bounded decoding, cache provenance, localization, and optional-field compatibility. No remaining actionable finding.

CodeRabbit’s incremental review explicitly covers the published head and reports no actionable comments / Minimal reviewer risk. The subsequent full review found a false refusal for Source Control/diff files whose workspace is marked local on its paired server. This PR merged at b0b0ce387c777efa29ac49a71120f377140bc56f before the correction was published. The correction is published in #26931, based on current main, with matching rendered before/after proof and regression tests. Project merge risk remains Medium because ownership checks span drag producers and terminal transports.

The generic docstring and issue warnings conflict with this repository’s concise-comment and maintainer issue guidance; no boilerplate comments or invented issue were added.

Agent skill upstream boundary

  • Not applicable; no upstream skill-installer material copied or translated.

Notes

The new drag field is optional and preserves payload version 1. No RPC, stream opcode, or persistent-state change. Nested SSH drops without verifiable server identity are refused. Fixtures use owned disposable files.

The unpublished local candidate 6ad7398e45bc was preserved after a protected push rejected the concurrent branch change. Its results are not attributed to this published head; the fresh results above qualify b0b0ce387c777efa29ac49a71120f377140bc56f directly.

Checklist

  • Focused change; user-facing behavior, mechanism, and rationale explained
  • Before/after visual proof attached
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and backwards compatibility considered
  • Local tests, typecheck, lint, changed-code checks, and build pass; CI covers remaining gates

@nwparker
nwparker requested a review from brennanb2025 as a code owner October 9, 2026 09:25
@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Workspace file-drag metadata now includes an optional runtime-environment ID alongside the workspace and execution host. File-explorer selections resolve an owner only when their paths share compatible ownership. Internal terminal drops validate source ownership against the target host and runtime environment before capturing the drop target. Rejected drops return a translated same-host message. Tests cover ownership resolution, accepted and rejected drops, and localized messages.


Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to b0b0c

Dragging files from a local workspace that a managed server owns into that server's terminal can be wrongly refused with the "same host" message. Fix the source host stamping before merging.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 21 files. (6 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check Passed The title clearly and concisely describes the main behavior change: restricting workspace file drops to the terminal's host.
Description check Passed The description follows the repository template and explains the user impact, implementation, rationale, issue context, visual proof, testing, compatibility considerations, and checklist status. The a…

Full details: Docstring Coverage

Explanation

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



  • 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/e2e/ssh-orcad-terminal-drop-owner.spec.ts (1)

190-221: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Make the managed-to-desktop drop case assert the refusal.

The poll on lines 190-198 accepts either outcome: a refusal toast, or a pasted filePath. If the drop is pasted, the else branch runs. Line 221 then fails, but only after the shell has already run cat on the desktop file. Line 220 can still pass when the desktop and remote files have the same path. The refusal is the required behavior for this test, so test for it directly. Wait for the toast. Then assert that the terminal output after REMOTE_DROP_RESULT does not contain filePath. Remove the else branch.

Proposed fix
-    await expect
-      .poll(async () => { ... return refused > 0 || echo.includes(filePath) })
-      .toBe(true)
-    const refused = page.getByText('Drop files from the same host as this terminal.', {
-      exact: true
-    })
-    if (await refused.count()) {
-      await page.keyboard.press('Control+c')
-      await expect(refused).toBeVisible()
-    } else { ... }
+    const refused = page.getByText('Drop files from the same host as this terminal.', {
+      exact: true
+    })
+    await expect(refused).toBeVisible()
+    expect(
+      ((await terminalText(page, floatingId)).split('REMOTE_DROP_RESULT').at(-1) ?? '')
+    ).not.toContain(filePath)
+    await page.keyboard.press('Control+c')

ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 700a7659-9bd8-46a4-b757-2f51025a6f00
📥 Commits

Reviewing files that changed from the base of the PR and between 1dab0d0 and 3773300.

📒 Files selected for processing (26)
  • .github/workflows/e2e.yml
  • config/scripts/ci-e2e-job-selection.mjs
  • config/scripts/ci-e2e-job-selection.test.mjs
  • config/scripts/pr-e2e-source-routing.mjs
  • src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerRow.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerVirtualRows.tsx
  • src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx
  • src/renderer/src/components/terminal-pane/terminal-drop-handler.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-internal-handler.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-internal-rejection-message.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-local-workspace.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-runtime-catalog-owner.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts
  • 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/renderer/src/lib/workspace-file-drag-source-runtime.test.ts
  • src/renderer/src/lib/workspace-file-drag-source.ts
  • src/renderer/src/lib/workspace-file-drag.test.ts
  • src/renderer/src/lib/workspace-file-drag.ts
  • tests/e2e/ssh-orcad-idle-exit.spec.ts
  • tests/e2e/ssh-orcad-terminal-drop-owner.spec.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.

@nwparker
nwparker force-pushed the nwparker/managed-terminal-file-drop-owner branch from 3773300 to 6d0355f Compare October 9, 2026 09:35
@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the refusal assertion finding in 6d0355fe51425584d3855cc998aa3d12b59c0a17: the test waits directly for the visible refusal, asserts no foreign path was inserted, and cancels the pending command. The branch is rebased onto current main 1dab0d076ef565c95b09ed4629000b34bc6245db.

The strengthened rendered test passes all three runs (50.7 seconds), including desktop and managed same-host controls. The rebased ownership/routing subset passes 149 tests across 10 files; full typecheck, lint, changed-code checks, fresh CLI/relay/Electron builds and commit hooks pass. Rendered test receipt.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nwparker
nwparker force-pushed the nwparker/managed-terminal-file-drop-owner branch from 6d0355f to b52d712 Compare October 9, 2026 09:47
@nwparker
nwparker force-pushed the nwparker/managed-terminal-file-drop-owner branch from 059769d to faee64c Compare October 9, 2026 11:01
@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Review-loop follow-up on faee64cc483fb820df03be39542fd6df28de2067, rebased onto main 049bf808ab24. CI found an incomplete header-drop fixture and an animation-cancellation screenshot failure. The fixture now stamps the real source identity; the screenshot wait tolerates cancelled animation promises and still requires full opacity. Direct visible refusal, no foreign path, and real desktop/managed same-host assertions remain.

148 affected tests / 16 files pass, full typecheck/lint/changed-quality/build/hooks pass, and all three real rendered shell controls pass (50.4 seconds). Previous CI failures are retained and described in the PR.

@coderabbitai review

@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

CodeRabbit has paused automatic reviews after the earlier commits. Please review the complete current diff at faee64cc483fb820df03be39542fd6df28de2067, including the CI fixture corrections and rebase onto main.

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nwparker
nwparker force-pushed the nwparker/managed-terminal-file-drop-owner branch from faee64c to f84c269 Compare October 9, 2026 11:39
@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main 4845ae8716b, preserving the new editor-watch CI routes. Final head: f84c2695ab69a0146cddf7575a7a8d7af2e1bdbe.

The previous CI Docker lane passed 19 cases and failed only this spec’s screenshot wait after the refusal and no-path assertions passed. It waited on toast animation promises until the toast disappeared. The test now checks mounted/full-opacity and captures the refusal immediately, before shell cancellation. Ownership assertions and both real same-host shell controls remain.

161 focused tests, full typecheck, oxlint, changed-code checks, fresh CLI/relay/Electron/server builds and hooks pass. Three actual hidden-renderer/Linux-host repetitions pass (57.5 seconds); screenshot inspected. No product code changed during this rebase follow-up.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

A workspace file dragged into a terminal now pastes only when its source
host (and paired-server namespace) matches the receiving terminal's
transport; otherwise the drop is refused with a toast.
@OrcaWin
OrcaWin force-pushed the nwparker/managed-terminal-file-drop-owner branch from f84c269 to b0b0ce3 Compare October 9, 2026 17:37
@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main 51e7181850b, keeping the newly merged browser-drop and terminal-root CI routes. Current head 6ad7398e45bc2dbfb91496b619f340c5588b6670.

The previous Docker lane passed22 cases; the mounted refusal toast stayed opacity0 until expiry in the hidden Linux renderer. Trace and failure screenshots inspected. The ownership proof now uses the supported reduced-motion preference while keeping the full-opacity/direct-refusal/no-foreign-path checks and both same-host shell controls. Three actual repeats pass52.6s; final fresh-build drop and terminal-root controls pass2/2 in33.6s.170 affected tests and final132 neighbor tests, tc/quality/builds/hooks pass.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Reviewing the current published head b0b0ce387c777efa29ac49a71120f377140bc56f. The earlier comment naming 6ad7398e45bc described an unpublished local candidate: its protected push was rejected after the branch changed. No remote commits were overwritten.

I am qualifying this published head with fresh focused tests and a freshly built hidden-renderer drop journey. The previous proof spec is used locally for validation; it was removed from the published branch by the concurrent update.

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 398de439-900a-4b8f-a14e-d1becf65d926
📥 Commits

Reviewing files that changed from the base of the PR and between 51e7181 and b0b0ce3.

📒 Files selected for processing (21)
  • src/renderer/src/components/editor/combined-diff/browse-files/combined-diff-file-tree-row-drag.test.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerRow.tsx
  • src/renderer/src/components/right-sidebar/FileExplorerVirtualRows.tsx
  • src/renderer/src/components/right-sidebar/file-explorer-drag-scroll-marker.test.tsx
  • src/renderer/src/components/terminal-pane/TerminalPaneHeaderOverlay.test.tsx
  • src/renderer/src/components/terminal-pane/terminal-drop-handler.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-internal-handler.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-internal-rejection-message.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-local-workspace.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-runtime-catalog-owner.test.ts
  • src/renderer/src/components/terminal-pane/terminal-drop-source-owner.test.ts
  • 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/renderer/src/lib/workspace-file-drag-source-runtime.test.ts
  • src/renderer/src/lib/workspace-file-drag-source.ts
  • src/renderer/src/lib/workspace-file-drag.test.ts
  • src/renderer/src/lib/workspace-file-drag.ts

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

Comment thread src/renderer/src/lib/workspace-file-drag-source.ts
@OrcaWin
OrcaWin merged commit 7d24509 into main Oct 9, 2026
39 checks passed
@nwparker

nwparker commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Published review fix at 7ccc09596c54a0d993419004a57b5f8f16bdd8ac.

Addressed the full-review finding: Source Control/combined-diff source stamping now converts a projected local workspace owner to its explicit server’s canonical runtime host. The real source writer and terminal handler reproduce the false refusal before the fix, then accept the paired-local drop afterward. The desktop control stays local with a foreign server focused.

203 tests/19 files, full typecheck, oxlint/changed-code gates, fresh E2E build and hooks pass. Three actual Files-drop journeys pass51.4s. A further real Source Control drag is fenced by its own shell marker and reads the managed host’s contents (17.2s). No native OS drag or Windows runtime claim.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Pull request is closed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

brennanb2025 added a commit that referenced this pull request Oct 20, 2026
…cs (#30897)

The daily full E2E run on main fails these specs every time because the
product moved on and PR CI only runs specs a PR touches:
- editor header menu renamed to File actions (#30129)
- terminal attention: an on-screen bell leaves no unread marker (#28637)
- terminal file drops carry their source host (#26830)
- single-choice questions auto-submit (#26288)
- phone terminal rows carry customTitle (#30037)
- gh/git preflight re-reads the login shell PATH (#25183)
- board drag starts after the target column is in view
- chat history anchor read after scroll settles
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.

2 participants