Skip to content

fix(runtime): deny paired clients host input, skill install, and unbounded dir browse - #18346

Open
fettpl wants to merge 6 commits into
stablyai:mainfrom
fettpl:fix/privileged-paired-rpc-gates
Open

fettpl wants to merge 6 commits into
stablyai:mainfrom
fettpl:fix/privileged-paired-rpc-gates

Conversation

@fettpl

@fettpl fettpl commented Sep 3, 2026

Copy link
Copy Markdown

ELI5

Paired web/phone clients were allowed to click the host mouse, install skill packages, set agent environment variables like PATH, and list any folder on the machine. Those actions now only work from the Orca host itself; directory browsing is limited to the home folder.

What Changed

  • computer.* RPC methods reject paired clientKind (mobile / runtime). Local unix-socket callers (clientKind === undefined) still reach the sidecar.
  • skills.install, skills.installBundle, skills.removeInstall, and skills.commitUpload throw the same unsupported-environment error skills.share already used for paired clients.
  • Paired settings.update still persists other settings, but agentDefaultEnv and agentDefaultArgs are stripped. Host settings types are unchanged.
  • files.browseServerDir / browseDirectory refuses paths outside os.homedir() (null bytes still rejected; Windows / still lists drive roots only).

Why

The RPC dispatcher is shared by the local unix-socket CLI and paired WebSocket clients. Mobile tokens have an allowlist; runtime-scoped pairing did not. A paired client could drive host input, install skills, persist launch env, and readdir arbitrary absolute paths. accounts.addClaudeFromConfigDir already documented the local-socket-only rule; this applies that gate to the privileged methods above.

Removing paired access is a visible behavior change for old clients (remote-wire Rule 1/3). Fail with an error string, not silence: old paired clients must not keep OS-input.

Linked Issue

Fixes #18269

Visual Proof

N/A — no visual or interaction change. This is a host RPC authorization bound.

Testing

  • Automated tests added/updated
  • I manually tested these changes locally (unit/typecheck coverage; no UI)

Verification run:

  • pnpm tc:node — exit 0
  • pnpm test src/main/runtime/rpc/methods — pass
  • pnpm test src/main/runtime/runtime-rpc/runtime-rpc-mobile-method-allowlist.test.ts — pass
  • pnpm test src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/methods/files.test.ts — pass (repository-project-operations.spec.ts is loaded via orca-runtime.test.ts)
  • pnpm test src/main/runtime/runtime-server-environment-commands.test.ts — pass
  • pnpm run check:code-quality:changed — pass

Platforms covered by tests: macOS (this run). Browse deny uses /etc on POSIX and C:\Windows on Windows; Windows / drive listing is unchanged (it.runIf(win32)).

Review

  • Security: Paired tokens can no longer inject OS input, install skill packages, persist PATH/LD_PRELOAD-style launch env, or list arbitrary host directories. Runtime-scoped pairing hits the same denies as mobile; this does not rely on MOBILE_RPC_METHOD_ALLOWLIST.
  • Cross-platform: Path bound uses isPathInsideOrEqual (Windows case/UNC-aware). Drive listing on win32 / still returns drive roots only; walking D:\src via browse is denied rather than re-opening /.
  • SSH / remote: Gates apply on the execution host (orca serve / paired runtime), including headless. Loss of contact is not involved; this is request-time clientKind denial. Browse uses the host's os.homedir().
  • Performance: Extra checks are O(1) string/path compares per call; no new I/O on the deny path (bound is checked before stat/readdir).
  • Backwards compatibility: Old paired clients get a visible error instead of OS-input. Local CLI and in-process callers are unchanged. files.browseServerDir remains on the mobile allowlist but is now homedir-bound.

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance

Checklist

  • This PR is small and focused
  • I explained what changed and why (including ELI5)
  • 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)

@pullfrog pullfrog 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.

ℹ️ No critical issues — two minor suggestions inline and one scope consideration.

Reviewed changes

This run reviewed the authorization gates the PR adds over the shared RPC dispatcher: computer.* now rejects any paired clientKind, the skills install/remove/commit-upload mutations reject paired callers with the existing unsupported-environment code, settings.update strips agentDefaultEnv/agentDefaultArgs for paired clients, and files.browseServerDir/browseDirectory bounds listing to os.homedir(). Coverage is solid — the computer gate is exercised across all 15 methods for both mobile and runtime, and every new assertion checks an exact rejection string/code plus that the sidecar/runtime method was never called.

  • computer.* host-only gate — a new assertHostOnlyClient rejects every computer method (input and observe alike) for paired clients; local callers still reach the sidecar.
  • Skill-mutation gaterejectPairedSkillMutation throws agent_skill_sharing_unsupported_environment from install/installBundle/removeInstall/commitUpload and reuses it for skills.share.
  • Settings env/args strip — paired settings.update drops agentDefaultEnv/agentDefaultArgs while persisting the rest.
  • Homedir browse boundbrowseDirectory resolves against homedir() and rejects paths outside it before any stat/readdir.

ℹ️ The browse bound is universal, not paired-only

The files.browseServerDir gate lives inside RuntimeServerEnvironmentCommands.browseDirectory with no clientKind check, so it restricts local unix-socket and in-process callers just as much as paired clients. The PR frames the threat as a paired-client escape, but the fix also removes the host's own ability to browse /srv, /opt, /mnt, /tmp, or external drives — a potential regression for headless orca serve hosts whose repos commonly live outside $HOME. If that is intended, fine; if not, gate the bound on clientKind !== undefined and leave local browsing unbounded.

Technical details
# Browse homedir bound scope

## Affected sites
- src/main/runtime/runtime-server-environment-commands.ts:27-32 — `assertAllowedServerBrowsePath` runs for every caller, with no `clientKind` discriminator.
- src/main/runtime/rpc/methods/files.ts:218-220 — `files.browseServerDir` forwards to `runtime.browseServerDir` without a `clientKind` check.

## Required outcome
- Decide whether local host browsing outside `$HOME` must stay available, and if so scope the deny to paired `clientKind` (or exempt local callers).

## Open questions for the human
- Is the directory browser expected to reach repos outside `$HOME` on headless hosts (e.g. `/srv`, `/opt`)?

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/runtime/runtime-server-environment-commands.ts Outdated
Comment thread src/main/runtime/rpc/methods/skills.ts Outdated
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

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

The PR restricts computer RPC methods and skill mutations to the host runtime. It removes agent launch environment and argument settings from paired-client updates. It limits server directory browsing to paths inside or equal to the home directory. Skill deletion and preview requests on non-local targets are rejected before any RPC call. Tests cover paired-client rejection, local request behavior, and valid and invalid browse paths.

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to 75ae5

On Windows, selecting a drive from the server browser now fails. This is a bounded navigation issue; the previously reported paired-client skill-operation gaps have been closed.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Issue #18269 requires files.browseServerDir to allow the home directory, its descendants, and an already-allowed worktree root. resolveAllowedServerBrowsePath only resolves and allows paths inside… Allow an already-allowed worktree root outside the home directory in resolveAllowedServerBrowsePath. Preserve the home boundary, NUL rejection, symlink protection, and Windows drive-root behavior. Add tests for an allowed worktree root ou…
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 13 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary changes: restricting paired-client host input, skill operations, and directory browsing.
Description check ✅ Passed The description covers the required sections, linked issue, user impact, security rationale, cross-platform considerations, testing, and checklist. It is complete enough for review, although the AI Di…
Out of Scope Changes check ✅ Passed The RPC guards, settings filtering, browse validation, tests, and renderer skill-delete restrictions support the coding requirements in issue #18269. No unrelated change appears in the reviewed summar…
Full details: Linked Issues check

Explanation

Issue #18269 requires files.browseServerDir to allow the home directory, its descendants, and an already-allowed worktree root. resolveAllowedServerBrowsePath only resolves and allows paths inside the real home directory. The tests cover home descendants, NUL rejection, symlinks, outside paths, and Windows drive roots, but they do not cover an allowed worktree root outside home. The paired-client RPC guards, local access, settings filtering, visible errors, and clientKind checks are implemented and tested.

Resolution

Allow an already-allowed worktree root outside the home directory in resolveAllowedServerBrowsePath. Preserve the home boundary, NUL rejection, symlink protection, and Windows drive-root behavior. Add tests for an allowed worktree root outside home and a path outside both allowed locations.


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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/runtime/rpc/methods/skills.ts (1)

97-104: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Authorization Bypass (CWE-862): Missing Authorization

Reachability: External · Exploitability: Moderate

Guard skills.delete for paired callers.

Pass clientKind to the handler and call rejectPairedSkillMutation(clientKind, 'Deleting skills') before runSkillDeleteRequest. Add skills.delete to the paired-client test matrix.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: fe4c6d69-af7f-4b2d-8d58-557194d3ec71

📥 Commits

Reviewing files that changed from the base of the PR and between 720c329 and 29770736154f58430205c71dbc39e6d12a88bcb4.

📒 Files selected for processing (9)
  • src/main/runtime/orca-runtime-tests/repository-project-operations.spec.ts
  • src/main/runtime/rpc/methods/client-ui.test.ts
  • src/main/runtime/rpc/methods/client-ui.ts
  • src/main/runtime/rpc/methods/computer.test.ts
  • src/main/runtime/rpc/methods/computer.ts
  • src/main/runtime/rpc/methods/skills.test.ts
  • src/main/runtime/rpc/methods/skills.ts
  • src/main/runtime/runtime-server-environment-commands.test.ts
  • src/main/runtime/runtime-server-environment-commands.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 1 remains after this review.

Comment thread src/main/runtime/runtime-server-environment-commands.ts Outdated

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

This run covered the two follow-up commits since the prior review, both closing open threads:

  • Gated skills.beginUpload / skills.uploadChunk — paired callers now hit rejectPairedSkillMutation before opening an upload session or appending chunk bytes, closing the staged-but-never-committed upload hole. The paired-caller test matrix now includes both methods.
  • Realpath browse boundresolveAllowedServerBrowsePath resolves realpath on both homedir() and the target before isPathInsideOrEqual, closing the symlink escape; a regression test covers a home symlink pointing outside home.

ℹ️ Realpath now also denies home symlinks to external storage

Resolving realpath on the target means a directory that is lexically inside $HOME but symlinks outside it (e.g. ~/projects -> /mnt/data/projects) is now rejected, even though the earlier lexical check would have listed it. That is the correct tightening for the paired-client threat, but it applies just as much to the local host browser and headless orca serve hosts whose large repos commonly live on a symlinked external drive. Worth confirming this is the intended reading of "browse limited to the home directory."

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

…unded dir browse

Paired mobile and runtime sockets could drive computer-use, install skills,
persist agentDefaultEnv, and readdir any absolute path through the shared RPC
dispatcher. Gate computer.* and skill install/remove/commit to local unix-socket
callers, strip launch env/args from paired settings.update, and limit
files.browseServerDir to the home directory.

Fixes stablyai#18269
files.browseServerDir used a lexical home check, so a symlink inside $HOME
that pointed outside (e.g. ~/link -> /etc) still listed the target. Resolve
realpath of the requested path and of homedir before isPathInsideOrEqual.

skills.beginUpload and skills.uploadChunk were still reachable from paired
clients after commitUpload was gated, so a client could fill disk with
staged chunks. Apply the same host-only rejectPairedSkillMutation gate.
@fettpl
fettpl force-pushed the fix/privileged-paired-rpc-gates branch 2 times, most recently from 0dc136c to 6bf19ed Compare September 18, 2026 11:34

@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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (2)

🟠 Major · Reject paired runtime callers from both cancellation methods. · skills.ts:162-163

src/main/runtime/rpc/methods/skills.ts:162-163
🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🟠 Major | ⚡ Quick win

Authorization Bypass

Reachability: External
Exploitability: Moderate
CWE: CWE-862 — Missing Authorization

Reject paired runtime callers from both cancellation methods.

The mobile allowlist blocks these method names, but paired runtime callers can reach them. Both handlers omit clientKind, and both runtime methods cancel host-owned state using only an ID. Add the same host-only guard used by the other skill mutations.

Proposed fix
-    handler: (params, { runtime }) => ({
-      cancelled: runtime.cancelSharedSkillInstall(params.operationId)
-    })
+    handler: (params, { runtime, clientKind }) => {
+      rejectPairedSkillMutation(clientKind, 'Cancelling skill installation')
+      return { cancelled: runtime.cancelSharedSkillInstall(params.operationId) }
+    }
...
-    handler: (params, { runtime }) => runtime.cancelSkillUpload(params.uploadId)
+    handler: (params, { runtime, clientKind }) => {
+      rejectPairedSkillMutation(clientKind, 'Cancelling skill upload')
+      return runtime.cancelSkillUpload(params.uploadId)
+    }
🟠 Major · Reject paired callers before deleting skills. · skills.ts:97-104

src/main/runtime/rpc/methods/skills.ts:97-104
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Reject paired callers before deleting skills.

skills.delete is callable through callRuntimeRpc for capable remote runtimes. Its handler omits rejectPairedSkillMutation, unlike the adjacent skill mutations. The request reaches runSkillDeleteRequest, which binds non-WSL targets to nativeSkillInstallFilesystem and removes staged skill paths. A paired mobile or runtime caller can therefore delete skills on the executing host.

-    handler: async (params, { runtime }) =>
-      runSkillDeleteRequest(
+    handler: async (params, { runtime, clientKind }) => {
+      rejectPairedSkillMutation(clientKind, 'Deleting skills')
+      return runSkillDeleteRequest(
         params,
         resolveDiscoveryTarget(params.target ?? {}, runtime),
         skillDeleteDependencies(runtime)
       )
+    }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: d8a97c8b-a7e4-48b8-9efa-d2e54e4de8a8

📥 Commits

Reviewing files that changed from the base of the PR and between 29770736154f58430205c71dbc39e6d12a88bcb4 and 6bf19ed.

📒 Files selected for processing (8)
  • src/main/runtime/rpc/methods/client-ui.test.ts
  • src/main/runtime/rpc/methods/client-ui.ts
  • src/main/runtime/rpc/methods/computer.test.ts
  • src/main/runtime/rpc/methods/computer.ts
  • src/main/runtime/rpc/methods/skills.test.ts
  • src/main/runtime/rpc/methods/skills.ts
  • src/main/runtime/runtime-server-environment-commands.test.ts
  • src/main/runtime/runtime-server-environment-commands.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Comment thread src/main/runtime/runtime-server-environment-commands.test.ts Outdated
Paired mobile/runtime clients could still delete host skills or cancel
host-owned install/upload state. Gate those RPCs the same way as the
other skill mutations.
@fettpl

fettpl commented Sep 23, 2026

Copy link
Copy Markdown
Author

Paired callers can no longer reach skills.delete, skills.cancelInstall, or skills.cancelUpload. They now hit rejectPairedSkillMutation before any host filesystem or in-flight operation work. Local (unpaired) callers are unchanged.

c9afaaf

@pullfrog pullfrog 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.

Important

The new paired-client gate on skills.delete also denies Orca's own desktop-to-remote-runtime skill management, which the renderer explicitly implements — see the inline note.

Reviewed changes

This run re-reviewed the delta since the prior pullfrog review (commit c9afaaf), which extends the paired-client deny to three more skill methods:

  • skills.delete gatedrejectPairedSkillMutation(clientKind, 'Deleting skills') now runs before runSkillDeleteRequest.
  • skills.cancelInstall / skills.cancelUpload gated — both cancellation handlers now reject paired callers; skills.share was refactored onto the shared helper with its message preserved.
  • Test matrix extendedcancelInstall/cancelUpload join the paired-caller rejection table, and a new skills.delete test asserts the deny precedes listRepos.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/main/runtime/rpc/methods/skills.ts
Runtime-scoped pairing is the same WebSocket as web/phone. Keep delete
host-local so the UI does not offer an action the RPC already denies.

@pullfrog pullfrog 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.

Important

The renderer half of the fix hides the delete affordance for {kind:'environment'} targets but not for the paired web client, whose active skill target resolves to {kind:'local'} — see the inline note.

Reviewed changes

This run re-reviewed the delta since the prior pullfrog review (commit c9afaaf), which the author answered by choosing to hide rather than exempt first-party clients:

  • Hid skill delete for paired targetsruntimeTargetSupportsSkillDelete now returns false for any target whose kind !== 'local', and assertSkillDeleteSupported throws PAIRED_SKILL_DELETE_UNSUPPORTED_MESSAGE before any RPC, so the desktop renderer no longer sends skills.delete/skills.previewDelete over a runtime-scoped pairing.
  • Reconciled delete tests — the environment-target tests now assert the deny path and that the remote capability probe is never consulted.

ℹ️ "Update Orca" is shown for a paired target that no update can enable

useSkillDeleteFlow's unsupportedReason treats "unsupported" as either a stale host or an unresolved target, so a focused paired runtime now renders "Update Orca on the selected machine to delete skills." Since runtimeTargetSupportsSkillDelete returns false for every non-local target, updating Orca on the selected machine cannot turn the action back on; the flow needs a third reason that names the host-only restriction instead.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

Comment thread src/renderer/src/runtime/runtime-skills-client.ts
Web always rides a pairing token, so deleteSupported is false and
preview/delete reject locally. Host previewDelete now fail-closes the
same way as delete. Browse tests compare realpath.

@pullfrog pullfrog 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.

ℹ️ No critical issues — the paired-web delete gap is closed. One minor test-robustness nit inline.

Reviewed changes

This run re-reviewed the delta since the prior pullfrog review (commit aecb7b9), which closes the paired-web delete gap:

  • Host gates skills.previewDelete — the handler now runs rejectPairedSkillMutation(clientKind, 'Deleting skills') before preview work, matching skills.delete, so a paired caller cannot even probe the delete plan.
  • Web delete affordance removedcreateSkillsApi().deleteSupported is now unconditionally false and the web previewDelete/delete reject locally, so a paired web/phone client no longer offers an action the host always rejects.
  • Testsskills.test.ts parameterizes the paired-rejection case over previewDelete and delete; a new web-host-capability-api.test.ts asserts the web probe stays false even when the host advertises skills.delete.v1; the browse suite now compares realpath.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

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

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Keep the home-bound guard and disable drive-root… · runtime-server-environment-commands.ts:56

src/main/runtime/runtime-server-environment-commands.ts:56
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep the home-bound guard and disable drive-root navigation.

The / response only enumerates Windows drives. A drive row is then treated as a directory, and clicking it calls browseServerDir('C:\\'). The server rejects that path because it is outside the home directory. Do not bypass the guard. Prevent drive-root rows from entering the directory-navigation path.

Suggested fix
diff --git a/src/renderer/src/components/sidebar/remote-file-browser-helpers.ts b/src/renderer/src/components/sidebar/remote-file-browser-helpers.ts
@@
 export function joinPath(
   resolvedPath: string,
   name: string,
   pathFlavor: FilesystemPathFlavor = 'posix'
 ): string {
@@
   return resolvedPath === '/' ? `/${name}` : `${resolvedPath}/${name}`
 }
 
+export function isDriveRootEntry(
+  resolvedPath: string,
+  name: string,
+  pathFlavor: FilesystemPathFlavor = 'posix'
+): boolean {
+  return pathFlavor === 'win32' && resolvedPath === '/' && isDrivePath(name)
+}
+
 export function parentPath(p: string, pathFlavor: FilesystemPathFlavor = 'posix'): string {
diff --git a/src/renderer/src/components/sidebar/RemoteFileBrowser.tsx b/src/renderer/src/components/sidebar/RemoteFileBrowser.tsx
@@
-import { filterEntries, joinPath, parentPath, type DirEntry } from './remote-file-browser-helpers'
+import {
+  filterEntries,
+  isDriveRootEntry,
+  joinPath,
+  parentPath,
+  type DirEntry
+} from './remote-file-browser-helpers'
@@
   const navigateInto = useCallback(
     (name: string) => {
+      if (isDriveRootEntry(resolvedPath, name, pathFlavor)) {
+        return
+      }
       navigate(joinPath(resolvedPath, name, pathFlavor))
     },
@@
-        if (entry.isDirectory) {
-          navigate(joinPath(listParentPath, entry.name, pathFlavor))
+        if (entry.isDirectory) {
+          if (!isDriveRootEntry(listParentPath, entry.name, pathFlavor)) {
+            navigate(joinPath(listParentPath, entry.name, pathFlavor))
+          }
         } else {

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: d438763e-ed89-4c5c-a9a3-4c7c955264b4

📥 Commits

Reviewing files that changed from the base of the PR and between aecb7b9 and 75ae5f3.

📒 Files selected for processing (5)
  • src/main/runtime/rpc/methods/skills.test.ts
  • src/main/runtime/rpc/methods/skills.ts
  • src/main/runtime/runtime-server-environment-commands.test.ts
  • src/renderer/src/web/preload-api/web-host-capability-api.test.ts
  • src/renderer/src/web/preload-api/web-host-capability-api.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/runtime/runtime-server-environment-commands.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review.

The command returns the canonical path; a symlinked $HOME made the
unresolved mkdtemp assertion host-dependent.

@pullfrog pullfrog 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.

✅ No new issues found.

Reviewed changes

This run re-reviewed the delta since the prior pullfrog review (commit 75ae5f3), a single test-only follow-up:

  • Realpath browse assertionrepository-project-operations.spec.ts now compares browseServerDir's resolvedPath against await realpath(tempRoot) instead of the unresolved mkdtemp path, so the assertion no longer depends on $HOME being canonical on the runner host. This was the one open Pullfrog thread and it is now resolved; no production behavior changed.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

This branch has not been deployed

No deployments
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.

Gate privileged RPCs the same way host-only account APIs are gated

1 participant