Repository navigation
Scoped Solenta Web devices and capability-declared MCP tools (#1530) - #1545
Conversation
Paired devices used to get full access: a phone could mint MCP pairing tokens or register an MCP server command. Each device now has scopes fixed at pairing (Read only / Steer threads / Full, plus files, git, terminal observe/type, preview, settings grants). webBridge checks the scope per channel on the host before dispatch and filters terminal:data pushes. electron/webScopes.js classifies all IPC channels; unlisted channels need full, and a test fails on any unclassified handler. Devices paired before this keep full access. External MCP tools now live in one EXTERNAL_TOOLS table with a declared capability; registration and every call check it. Adds a Copy MCP URL button to the pairing reveal. OAuth moves to #1541. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5f03ba9a2d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "files:tree", | ||
| "files:read", | ||
| "files:image", | ||
| "attachments:readImage", |
There was a problem hiding this comment.
Restrict arbitrary image reads to a privileged scope
A device paired with the “Read only” preset can invoke attachments:readImage with any known absolute image path and receive its bytes as a data URL. The handler deliberately accepts arbitrary host paths (electron/attachments.js:283-313), while this table otherwise reserves arbitrary host-path access for full, so a read-only phone or browser token can exfiltrate unrelated screenshots or photos outside every Solenta project. Classify this channel as full, or constrain it to attachment/workspace paths that the device is already authorized to read.
Useful? React with 👍 / 👎.
…review) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ope table (#1553) #1545 added a coverage test that every IPC handler is classified exactly once; #1542 (answerSecret) and #1551 (setFast) landed alongside it unclassified, so main's electron suite fails. setFast is steer like setReasoningEffort; answerSecret puts a value into the agent's run env, so it stays full-only. Co-authored-by: Willem <willem@willems-mbp.home> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ope table #1545 added a coverage test that every IPC handler is classified exactly once; #1542 (answerSecret) and #1551 (setFast) landed alongside it unclassified, so main's electron suite fails. setFast is steer like setReasoningEffort; answerSecret puts a value into the agent's run env, so it stays full-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1545 added the scope table while #1551 (setFast) and #1542 (answerSecret) added channels in parallel, so main's scope-table test fails. setFast is steer, like setReasoningEffort. answerSecret is full: a device has no need to plant a secret in a run's env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t/answerSecret web scopes #1435: bill a warm Claude process's cost growth, not its running total. #1436: worker-finished notice tells the orchestrator not to poll thread_status; saved notices with the old footer still fold. #1439: build devCoder on first use so importers don't stay alive ~4s. webScopes: threads:setFast (steer) and threads:answerSecret (full) were unclassified after #1545 landed alongside #1551 and #1542, failing main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes parts 1-2 of #1530. OAuth (part 3) moves to #1541, because the MCP endpoint listens only on loopback, so hosted agents can't reach it whatever the auth.
What changes
webBridgechecks the scope per channel before any handler runs, and only sendsterminal:datapushes to devices with terminal access.electron/webScopes.jsclassifies every IPC channel. Unlisted channels need full, and a test fails on any unclassified handler, which already caughtthreads:setGoalandgit:prRevertfrom main during the rebase.web-token. Until now a paired phone could callpairing:createandmcp:save.EXTERNAL_TOOLStable, each with a declared capability. Registration skips tools a pairing lacks, and every call re-checks before the handler runs.Calls worth reviewing
threads:runCommandandthreads:setVerifyCommandneed terminal type, because both run an arbitrary shell command.threads:purgeneeds full.Tests
electron/test/webScopes.test.js: table coverage,allowsandsanitizeScopes, the device-row migration, and denial plus push filtering over a real socket.pairing.test.js, and new scope-picker tests inwebAccessSection.test.tsx.🤖 Generated with Claude Code