fix(worker/ocs): read-only 模式未拦截文件写入#913
Merged
Merged
Conversation
… projectDir to OCS - Gateway: Send a synthetic delivered InputAck when a control command is intercepted to avoid UI lockup. - OpenCode Server Worker: Propagate the projectDir to OCS REST API calls via the directory query parameter to satisfy WorkspaceRoutingMiddleware.
OCS's permission system is an opt-in allowlist: when no rule matches a tool call, the default action is ALLOW — not ask or deny. The previous plan mode only injected a read-allow rule and assumed unmatched operations would be blocked. In reality, edit/write/bash/shell/patch all went through without any approval prompt. Additionally, each write tool must be denied individually because the agent can pivot between them (e.g. fall back to bash when edit is unavailable — confirmed empirically). Fix: inject explicit deny rules for edit, write, bash, shell, and patch in plan mode. Updated the misleading comment on the default case as well.
Parse permission tool args (JSON string / object / array) and render command, action, target, reason, allowed directories and patterns in dedicated sections instead of a raw JSON dump; surface toolAction / toolSummary as the card description. Expand extractFilePath / extractFileContent to accept more field-name variants (filePath, filepath, file, filename, replacementContent, codeContent, replacement, text) so OCS-side arg shapes render diffs. Localize the new labels and the 'unknown file' fallback in en/zh-CN.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
OCS (OpenCodeServer) Worker 的 workspace 只读约束失效:workspace 设为
read-only(plan 模式) 后,Agent 仍能直接改文件;workspace / auto-edit 层级的工作区边界也没被实际执行。根因
OCS 权限系统是 opt-in allowlist:工具调用未命中任何规则时,默认动作是 ALLOW,既不 ask 也不 deny。原代码在 plan 模式只注入了
read: allow一条规则,假设未匹配的操作会被拦截——实际上edit/write/bash/shell/patch全部直接放行。实测确认:即便给edit单独 deny,Agent 也会绕道bash(echo > file) 完成写入。更深的两个问题:
CreateWithBot返回的 snapshot 未同步WorkspaceID,workspace 边界对首次会话不生效。修复
按 6 个维度收紧 OCS 权限执行。
1. plan 模式从 ask-all 基线开始 (而非仅注入单条 read)
internal/worker/opencodeserver/commands.go— plan 模式注入*:ask通配基线,再选择性 allow 内建只读工具 (read / glob / grep / list / lsp / webfetch / websearch)。写入操作因此变成权限请求,而非被静默丢弃或绕行。custom / MCP / subagent 工具也落在 ask 基线上,不会形成绕过通道。2. 工作区边界:外部目录需审批
commands.go—acceptEdits与workspace层级显式注入external_directory: ask,工作区内的 edit 已 allow,工作区外则触发审批。auto-edit作为用户明确选择的 no-prompt 层级,external_directory走 allow,保留其语义。同时把allowed_tools白名单的注入限制在非 plan 模式下,避免在 read-only 基线上被一条 caller-supplied allow 规则重新打开写入。3. 首个 worker 即应用 workspace 上限
internal/gateway/bridge.go—SetWorkspaceID持久化了绑定,但无法改CreateWithBot返回的 snapshot。把si.WorkspaceID同步回 snapshot,使首个 worker (而非只有后续 resume) 即受 workspace 权限上限约束。4. 权限应用失败不再被吞掉
internal/worker/opencodeserver/worker.go—initSessionConn从无返回值改为返回 error;applyPermissions失败时清理cmd并向上冒泡,Start / Resume 路径相应释放资源。原先只打一条 warn 继续跑,worker 实际处于"权限未应用"的裸状态。5. 命令失败不再误发"已交付"ack
internal/gateway/handler.go—handleInput在 control command 返回 err 时跳过ackControlCommand,避免命令失败后 UI 因合成 "delivered" ack 假冻结。6. webchat 结构化渲染审批参数
webchat/components/assistant-ui/tools/PermissionApprovalCard.tsx— 解析权限工具参数 (JSON string / object / array 三种形态),分区块渲染 command / action / target / reason / 允许目录 / 允许模式,取代原来的原始 JSON dump。extractFilePath/extractFileContent扩展字段名变体 (filePath / filepath / file / filename / replacementContent / codeContent / replacement / text),兼容 OCS 侧 arg 结构。新增文案同步进 en / zh-CN。最终规则集
plan(read-only)*:ask基线 + read/glob/grep/list/lsp/webfetch/websearch allowacceptEdits/workspaceexternal_directory: askauto-editexternal_directory全 allowbypassPermissions测试
internal/worker/opencodeserver/—commands_test.go/worker_test.go覆盖各模式规则集、allowed_tools 在 plan 模式被忽略、external_directory分层、initSessionConn 错误冒泡internal/gateway/—conn_test.go验证首启 workspace 绑定;command_detection_test.go覆盖命令失败路径go test -race通过;webchat tsc + ESLint 通过文档
docs/guides/developer/remote-coding-agent.md与security-model.md同步更新 OCS 权限语义。Refs #789