9.1 权限模型设计

模型: claude-opus-4-6 (anthropic/claude-opus-4-6) 生成日期: 2026-02-17


AI Agent 能够执行 Shell 命令、修改文件、访问网络——这些能力在带来便利的同时也引入了巨大的安全风险。一个缺乏权限控制的 Agent 可能误删重要文件、泄露环境变量中的 API 密钥、或者执行危险的系统命令。权限控制系统是 OpenCode 安全架构的基石,它确保 Agent 的每一个敏感操作都在用户的知情和授权下进行。

本节将解析 OpenCode 权限系统的数据模型设计,包括三种权限动作、规则的定义结构、以及规则集的合并策略。

9.1.1 三种权限动作:allow、deny、ask

OpenCode 的权限系统基于三种基本动作(Action):

// permission/next.ts
export const Action = z.enum(["allow", "deny", "ask"])
动作
含义
效果

allow

允许

直接执行,不需要用户确认

deny

拒绝

直接阻止执行,抛出 DeniedError

ask

询问

暂停执行,弹出 TUI 对话框让用户决定

这三种动作构成了一个完整的决策空间:

  • allow 是最宽松的——适用于低风险操作或用户已明确信任的操作(如读取项目内的文件)。

  • deny 是最严格的——适用于绝对不应该发生的操作(如 Agent 读取 .env 文件中的敏感信息)。

  • ask 是折中方案——也是默认行为。当没有任何规则明确匹配时,系统会回退到 ask

这种三值设计比简单的"允许/拒绝"二值模型更加灵活。ask 动作让用户在首次遇到某类操作时做出决定,并且可以选择"仅此一次"或"始终允许",从而在安全性和使用便捷性之间取得平衡。

9.1.2 PermissionNext.Rule:permission + pattern + action

权限规则(Rule)是权限系统的原子单位。每条规则由三个字段组成:

permission 字段标识了这条规则适用于哪种权限类型。OpenCode 中的每个工具在定义时都声明了自己需要的权限名称:

工具
权限名称
说明

Bash

bash

命令执行权限

Edit / Write / Patch

edit

文件编辑权限

Read

read

文件读取权限

Glob

glob

文件查找权限

Grep

grep

内容搜索权限

Task

task

子 Agent 调度权限

Skill

skill

Skill 加载权限

WebFetch

webfetch

网页抓取权限

WebSearch

websearch

网页搜索权限

LSP

lsp

语言服务器权限

TodoWrite

todowrite

Todo 写入权限

TodoRead

todoread

Todo 读取权限

ExternalDirectory

external_directory

外部目录访问权限

CodeSearch

codesearch

代码搜索权限

doom_loop

循环检测权限(特殊)

pattern 字段是一个通配符模式,用于进一步限定规则的匹配范围。例如:

  • "*" —— 匹配所有模式(最宽泛)

  • "ls *" —— 匹配 ls 开头的命令

  • "/home/user/.env" —— 匹配特定文件路径

  • "*.md" —— 匹配所有 Markdown 文件

action 字段指定当规则匹配时应该执行的动作。

一些具体的规则示例:

9.1.3 Ruleset:规则集合与合并策略

RulesetRule 的有序数组:

从配置到 Ruleset 的转换

用户的权限配置通常以更简洁的格式书写(在 opencode.jsonagent.permission 字段中)。fromConfig() 函数负责将这种简洁格式转换为标准的 Ruleset

expand() 函数处理路径中的 ~$HOME 前缀,将它们展开为实际的 home 目录路径:

Ruleset 的合并策略

多个来源的 Ruleset 需要被合并为一个统一的规则集。OpenCode 的合并策略非常简洁:

合并就是简单的数组拼接。这意味着后面的规则会覆盖前面的规则——因为在评估时使用的是 findLast()(从后往前查找第一个匹配的规则)。这种"后来者优先"的设计让权限层级自然形成了一个 优先级链

这种设计的优雅之处在于,它不需要复杂的优先级标记或权重计算——仅通过数组中的位置就决定了规则的优先级。我们将在 9.2 节中详细分析评估引擎的 findLast() 逻辑。

关于双系统共存

细心的读者可能注意到,OpenCode 源码中实际上有两个权限系统:

  1. PermissionNextpermission/next.ts):新版权限系统,基于 Rule/Ruleset 模型。

  2. Permissionpermission/index.ts):旧版权限系统,基于 type + pattern 模型。

两个系统目前共存于代码库中。PermissionNext 是更新、更完善的实现,它被 Session 系统和 Processor 主要使用。旧版 Permission 仍在部分代码路径中保留(如 Plugin 的 permission.ask 钩子),但正在逐步被 PermissionNext 取代。

本章主要分析 PermissionNext 的实现。两个系统的核心思路一致——基于"权限类型 + 匹配模式 → 动作"的规则模型。


本节小结

OpenCode 的权限系统基于三值动作模型(allow/deny/ask),其中 ask 作为默认行为确保了安全优先的设计哲学。权限规则由 permission(权限类型)、pattern(通配符模式)和 action(动作)三个字段组成。多个来源的 Ruleset 通过简单的数组拼接合并,利用 findLast() 评估策略实现"后来者优先"的覆盖语义,使得权限层级自然形成优先级链。

Last updated