OpenCode权限扫盲

结城 AI 7 次阅读 2189 字 发布于 17 天前 预计阅读时间: 10 分钟


在使用AI编程时,信任和可控是一对永恒的矛盾。

既希望工具能自动完成大量工作,又不希望它越权执行危险操作。

OpenCode 通过一套灵活的权限配置,让开发者在“自动运行”“弹窗询问”和“直接阻止”之间找到平衡点。

新的权限配置系统

v1.1.1​ 版本之前,OpenCode 用一个布尔型的 tools 配置来控制工具调用是否需要审批。

这种开关过于粗糙,无法针对不同操作做精细化管理。

新版本中,布尔控制旧配置已被合并进 permission 字段,权限功能更强大,同时保留了对旧配置的兼容,已有的项目不会受到影响。

同时,权限配置不会影响性能,因为权限检查是在操作执行前进行的,不会影响 AI 的响应速度。

本文撰写时刻,最新的版本为v1.15.13

权限匹配模式

权限模式匹配时要注意参数的完整性。

例如,"grep *"​ 能够匹配 grep pattern file.txt​,而单独一个 "grep" 规则会因为不包含参数部分而匹配失败,导致操作被拦截。

同样,像 git status​ 这样的命令如果没有参数能正常执行,但一旦带上参数,就需要用 "git status *" 来覆盖。

权限配置不会影响性能,因为权限检查是在操作执行前进行的,不会影响 AI 的响应速度。

允许、询问、拒绝

每个权限规则最终都会落到三种处理方式之一:

  • allow:自动执行,无需打扰使用者。
  • ask:弹出确认框,等待人为批准。
  • deny:直接拦截,不会执行。

三态模型覆盖了从完全信任到严格禁止的各类场景。

全局与局部策略

全局策略

最简单的配置是直接给所有操作指定一个统一策略。无需详细的权限配置。

例如,让所有工具调用都先询问:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": "ask"
}

也可以用 "allow" 彻底放开所有操作,不过在生产环境中很少会这么用。相当于对所有的请求均不验证,非常危险。

局部策略

对于具体权限也可以按工具分类。

下面这个例子设置了全局默认“询问”,但对 bash​ 命令和 edit 编辑操作单独放行或拒绝:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": { 
    "*": "ask",
    "bash": "allow",
    "edit": "deny"
  }
}

这里的 "*" 是一个通配符,代表所有未单独列出的工具。规则合并时,具体的工具规则会覆盖全局规则。

此分类含义是,默认所有操作都需要询问,但是bash操作允许执行,但是编辑操作拒绝执行。

精细到参数级别的颗粒度

OpenCode 的权限系统甚至可以匹配命令的具体参数。通过对象语法,能让同一工具在不同输入下表现出不同行为。

我们可以默认使得所有的操作都询问或者拒绝,但是针对某些方案允许执行。

一个典型的例子是对 bash 做区别对待:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": { 
    "bash": { 
      "*": "ask",
      "git *": "allow",
      "npm *": "allow",
      "rm *": "deny",
      "grep *": "allow"
    },
    "edit": { 
      "*": "deny",
      "packages/web/src/content/docs/*.mdx": "allow"
    }
  }
}

这段配置的意思是:运行 shell 命令时,默认需要询问,但所有 git​、npm​、grep​ 开头的命令自动放行,而 rm 删除命令则坚决阻止。

对于文件编辑操作,全局禁止修改,唯独允许改动 packages/web/src/content/docs/​ 路径下的 .mdx 文件。

匹配规则按顺序评估,最后匹配到的规则生效

常见的方案是把 "*" 兜底规则写在最前面,然后再写更具体的例外情况,这样后面的规则就能覆盖前面的全局默认。

通配符的用法

模式匹配用到了简单的通配符语法:

  • * 匹配任意数量的字符(包括零个)。
  • ? 匹配恰好一个字符。
  • 其他字符会按字面量精确匹配。

巧用home目录扩展

在写路径模式时,可以用 ~​ 或 $HOME 代表当前用户的 home 目录。

例如 ~/projects/*​ 会展开为 /Users/用户名/projects/*

开箱即用的默认值

如果不在配置文件里写任何 permission 内容,OpenCode 会以一套相当宽松但又兼顾安全的默认规则启动:

  • 大多数权限默认 "allow",即自动执行。
  • doom_loop​ 和 external_directory​ 默认 "ask",避免无限循环和越界访问。
  • read​ 虽然全局允许,但对 .env​ 默认拒绝读取 .env​ 和 .env.*​,只会放行 .env.example

等效的默认配置可以理解为:

{ 
  "permission": { 
    "read": { 
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow"
    }
  }
}

外部目录与死循环检测

除了按照工具划分权限,OpenCode 还内置了两个特殊的安全守卫:

external_directory

external_directory 会在工具调用涉及工作目录之外的文件路径时触发。比如,即便用 ~ 展开了路径,那个路径如果不在 OpenCode 的启动工作区内,仍然被视为外部目录。

想让 AI 读写外部目录,必须显式授权。

举个例子,允许访问 ~/projects/personal/ 下的所有内容:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": { 
    "external_directory": { 
      "~/projects/personal/**": "allow"
    }
  }
}

一旦某个外部目录被允许,它会继承当前工作区的默认权限。默认情况下 read​ 是允许的,因此读取外部文件不会受阻。如果只想让 AI 看但不能改,可以在 edit 权限里单独加上拒绝规则:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": { 
    "external_directory": { 
      "~/projects/personal/**": "allow"
    },
    "edit": { 
      "~/projects/personal/**": "deny"
    }
  }
}

这样既开放了阅读,又保护了文件不被意外修改。

doom_loop

doom_loop 是另一个智能防护:当同一个工具调用在输入完全不变的情况下重复出现三次,说明系统可能陷入了死循环,此时 OpenCode 会主动弹窗询问,避免空转消耗资源。这个权限默认就是 "ask",通常不需要改动。

完整的权限清单

OpenCode 可配置的权限覆盖了所有核心操作,每一项都以工具名称作为键:

  • read:读取文件,匹配文件路径。
  • edit:所有文件修改(包括编辑、写入、补丁)。
  • glob:文件名匹配搜索,匹配 glob 模式。
  • grep:内容搜索,匹配正则表达式。
  • bash​:执行 shell 命令,匹配解析后的命令(如 git status --porcelain)。
  • task:启动子任务代理,匹配子代理的类型。
  • skill:加载技能模块,匹配技能名称。
  • lsp:执行 LSP 查询(目前不支持颗粒度控制)。
  • question:运行中向使用者提问。
  • webfetch:抓取 URL,匹配目标网址。
  • websearch:网络搜索,匹配查询字符串。
  • external_directory:工具操作触碰到项目工作目录外的路径时触发。
  • doom_loop:同一工具调用输入完全一致且连续重复 3 次时触发。

询问弹窗选项

当某个操作被设置为 "ask" 后,OpenCode 的界面会弹出确认框,提供三个选择:

  • once:仅批准本次请求。
  • always​:根据工具建议的模式,批准当前会话中所有匹配的后续请求(比如 bash​ 会建议允许类似 git status* 这样的安全前缀)。
  • reject:拒绝本次请求,不执行。

同理,默认的权限配置下,如果Agent想要执行超出权限的修改或者规划,如果不做答也会默认终止执行。

Agent的权限覆盖

OpenCode 支持为不同的Agent单独设置权限。Agent的权限配置会与全局配置合并,并且Agent规则拥有更高的优先级。

Agent 级别的权限优先级最高。如果想要恢复默认的配置,需要删除配置文件中的 permission 部分,Opencode 会使用默认的安全配置。

例如,全局配置里 git commit * 被直接拒绝,但在一个名为 “build” 的Agent中,可能希望提交操作变为询问,以便在构建脚本中灵活判断:

{ 
  "$schema": "https://opencode.ai/config.json",
  "permission": { 
    "bash": { 
      "*": "ask",
      "git *": "allow",
      "git commit *": "deny",
      "git push *": "deny",
      "grep *": "allow"
    }
  },
  "agent": { 
    "build": { 
      "permission": { 
        "bash": { 
          "*": "ask",
          "git *": "allow",
          "git commit *": "ask",
          "git push *": "deny",
          "grep *": "allow"
        }
      }
    }
  }
}

此外,Agent权限也可以在 Markdown 格式的代理定义文件中直接声明:

---
description: Code review without edits
mode: subagent
permission:
  edit: deny
  bash: ask
  webfetch: deny
---

Only analyze code and suggest changes.
markdown

给时光以生命,给岁月以文明
最后更新于 2026-06-15