Skip to content

fix(mobile): Save plan to workspace is off for connections without file write access - #28292

Open
only21mil wants to merge 2 commits into
pingdotgg:mainfrom
only21mil:fix/audit-m003
Open

only21mil wants to merge 2 commits into
pingdotgg:mainfrom
only21mil:fix/audit-m003

Conversation

@only21mil

@only21mil only21mil commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On mobile, a connection without the filesystem:write scope still shows an enabled "Save to workspace" button on a proposed plan. Tapping it, entering a path and saving fails only when the server rejects the write. The button should be off for that connection, as it already is on web.

Change

projects.writeFile was missing from CLIENT_GUARDED_RPC_SCOPES, so clientRpcRequiredScopes returned no scopes and the command's permissionAtom was always true. The mobile card reads that atom.

  • Add projects.writeFile → filesystem:write to the client map.
  • Remove the server's own copy of that entry. RPC_REQUIRED_SCOPES spreads the client map, so the server still requires the same scope.
  • Add a projects.writeFile case to commandPermissions.test.ts, shaped like the OTLP grant test. It stays a separate case so it merges cleanly with feat(server): run CLIProxyAPI on an environment and manage its accounts in Settings #27388, which turns that test into a table. Once both land, it can become a row there.
  • projectCommands.test.ts now mounts the mocked session atom before setting it, as the commandPermissions.test.ts setup does. With writes now checked on the client, an unmounted mock was dropped and the write test waited forever.

Web already gates its Save to workspace and file editor on the same scope, so nothing changes there. Copying files when adding a project to another machine now fails on the client with "This connection requires filesystem:write" instead of on the server, and is reported in the same list.

Scope and approval

There is no issue. This is a one-entry fix of an obvious bug: AGENTS.md says protected client mutations go in CLIENT_GUARDED_RPC_SCOPES, and this method was left out while the server already guarded it. Server authorization doesn't change. This PR adds no editing workflow and changes only whether the existing plan-save button is enabled.

Prior PRs

#16927 by @camchis added the same map entry and a matching permission test as part of a mobile file editor. It was closed because the editor workflow needs approval in #16500. Closing it didn't touch this guard. This PR takes only the guard, for the save button mobile already ships.

Verification

  • vp test run packages/client-runtime/src/state/commandPermissions.test.ts: the new projects.writeFile case fails on main (permissionAtom is true with no grant) and passes with the fix. 19 tests pass.
  • vp test run packages/client-runtime/src/state/projectCommands.test.ts apps/server/src/auth/RpcAuthorization.test.ts: all pass.
  • vp run check:changed: format, lint, knip, typecheck and tests all pass.
  • iOS 26.5 Simulator and Android 16 Emulator, development client, each paired with a token that has the standard scopes minus filesystem:write. Same session and thread in both states; only the two permission files differ between them.

iOS before: Save to workspace is enabled.

Before: Save to workspace enabled without write access

iOS before: saving fails on the server.

Before: save rejected by the server

iOS after: Save to workspace is dimmed and disabled.

After: Save to workspace disabled without write access

Android before: Save to workspace is enabled.

Android before: Save to workspace enabled without write access

Android before: saving fails on the server.

Android before: save rejected by the server

Android after: Save to workspace is dimmed and disabled.

Android after: Save to workspace disabled without write access

The machine name is blanked out of the Android thread header.

Not checked:

  • Web and desktop. Their Save to workspace already checks the same scope, so nothing changes on screen there.

Generated with Claude Opus 5.5 and GPT-6.1 Terra in T3 Code Nightly

…le write access

projects.writeFile was missing from CLIENT_GUARDED_RPC_SCOPES, so its
permissionAtom was always true and mobile's Save to workspace button stayed
enabled for sessions without filesystem:write, failing only on the server.
Move the entry into the client map that the server already spreads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Oct 31, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 2602632

Macroscope's review found this PR approvable — The client now requires file-write access before enabling workspace saves or sending write requests. Server permissions remain unchanged, so this prevents already-forbidden attempts without expanding access.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The client permission map assigns AuthFilesystemWriteScope to projectsWriteFile. The server required-scope map no longer includes that method. Tests cover the client permission behavior and update the project-command test harness.

Changes: RPC permission mappings

Layer / File(s) Summary
Update RPC permission mappings
packages/contracts/src/clientRpcPermissions.ts, apps/server/src/auth/RpcAuthorization.ts
The client guard maps projectsWriteFile to AuthFilesystemWriteScope. The server required-scope map no longer includes projectsWriteFile.
Test client permission behavior
packages/client-runtime/src/state/commandPermissions.test.ts, packages/client-runtime/src/state/projectCommands.test.ts
A test checks that an orchestration-only grant does not permit projectsWriteFile, while a filesystem-write grant in both scopes and permissions makes permission available and authorization succeed. The project-command test harness mounts the session atom before setting its state.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: t3dotgg

Merge Risk: Minimal · up to 5d119

Plan saving now reflects write permission. No merge-blocking issue was identified.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title identifies the mobile plan-save permission fix.
Description check Passed The description covers the problem, change, scope, verification, screenshots, and unchecked platforms.
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

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 2602632 and 5d1193b.

Files selected for processing: 4

  • apps/server/src/auth/RpcAuthorization.ts
  • packages/client-runtime/src/state/commandPermissions.test.ts
  • packages/client-runtime/src/state/projectCommands.test.ts
  • packages/contracts/src/clientRpcPermissions.ts
Files with no reviewable changes: 1

  • apps/server/src/auth/RpcAuthorization.ts

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

@maria-rcks

maria-rcks commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified the shared permission guard at 2602632166c0b0b455580316869bb5bc79e6aa99, against github/main at 575579d68a, with one isolated dev server running at a time. no code changes were needed.

used repository playwright with /usr/bin/google-chrome. created a project through the app and ran codex gpt-6.1-sol to produce a real proposed plan. reused that app-created state on the pr. paired real full-access and restricted sessions; the restricted session retained orchestration:operate but lacked filesystem:write.

exercised the actual shared projectEnvironment.writeFile command and its permissionAtom from the running browser's app registry and authenticated connection, without substituting session state:

main: permissionAtom=true; write requests sent=1
      server rejects: The authenticated token is missing required scope: filesystem:write.
pr:   permissionAtom=false; write requests sent=0
      client rejects: This connection requires filesystem:write.
pr:   direct live RPC bypassing client guard still rejected by server
      denied files absent on disk

nearby behavior passed: full-access web plan saving on both revisions, with the written file matching the plan; restricted-session markdown download; and another real codex turn on the pr returning plan remains readable. the web save menu remains disabled without write access on both revisions, as expected from its existing separate guard.

40 focused tests passed on blacksmith across commandPermissions.test.ts, projectCommands.test.ts, and RpcAuthorization.test.ts. reported non-skipped github checks also pass.

before, main's existing web guard with the restricted connection:

main restricted connection: web save remains disabled

after, pr with the same plan and restricted scopes:

pr restricted connection: web save remains disabled

full-access save on the pr, with actual file contents checked afterward:

pr full-access plan save interaction

command and runtime transcript

Not verified

native ios/android button rendering and taps: this linux vm has no attached device or emulator. the shared command and permission used by the mobile card were exercised, but this is not native ui verification. desktop shell, other providers, relay/tunnel, and multi-environment file copying were not exercised.

Merge with main

Note

Written by claude-opus-5-5 on behalf of Maria

merged current main into the branch at 5d1193bdf4 (merge commit, no rebase). the only conflict was in commandPermissions.test.ts, where main added a providerAuthRemoveMethod case at the same spot as this pr's projectsWriteFile case. both cases are kept. no other code changed. vp run check:changed and the three touched test files pass.

# Conflicts:
#	packages/client-runtime/src/state/commandPermissions.test.ts

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

size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants