OpenCode 权限管理系统完全指南:打造安全可控的 AI 编程环境

OpenCode 权限管理系统完全指南:打造安全可控的 AI 编程环境

引言

随着 AI 编程助手在日常开发中的深度介入,安全问题变得愈发重要。一个能够随意读写文件、执行 Shell 命令、访问网络的 AI 工具,如果缺乏细粒度的权限控制,就可能成为安全隐患。OpenCode 从 v1.1.1 开始对权限系统进行了全面重构,将原来简单的 tools 开关升级为功能强大的 permission 配置体系,让开发者能够精确控制 Agent 的每一个操作。本文将系统讲解 OpenCode 权限管理的完整用法,帮助你构建既高效又安全的 AI 编程工作流。

为什么需要权限控制

在日常使用 AI 编程助手时,以下场景你可能并不陌生:

  • Agent 为了排查问题,读取了 .env 文件内容并显示在终端中
  • 批量重构时,Agent 意外修改了你不希望被改动的锁文件
  • Agent 执行了 rm -rf 这样的危险命令
  • 在讨论代码时,Agent 自动联网抓取了未经验证的外部内容

这些场景的共同特征是:Agent 的操作范围超出了你的预期,而你缺少一种精细控制的能力。OpenCode 的权限系统正是为解决这些问题而设计的——它允许你对文件的读取和编辑、Shell 命令执行、网络访问、外部目录访问、子 Agent 调用等操作设置精确的"允许/询问/拒绝"规则。

权限基础:三种决策结果

OpenCode 中每条权限规则最终都会得出三种结果之一:

| 结果 | 含义 | 适用场景 |
|------|------|----------|
| allow | 无需确认,自动放行 | 信任的常规操作,如 git status |
| ask | 弹窗询问用户 | 需要人工判断的操作,如执行 curl 命令 |
| deny | 直接拒绝 | 危险操作或敏感文件访问 |

默认情况下,OpenCode 的策略比较宽松——大多数权限默认 allow,但有两个重要例外:doom_loop(死循环检测)和 external_directory(外部目录访问)默认为 ask。此外,.env 系列文件的读取也有特殊保护:

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

这意味着 Agent 默认不允许读取 .env.env.production 等敏感文件,但允许读取 .env.example 这类模板文件。

快速上手:简单模式

最简单的配置方式是使用字符串简写,为整个工具类别设置统一策略:

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

上述配置的意思是:默认所有操作都需要询问(*: "ask"),唯独 Shell 命令自动放行(bash: "allow"),而所有文件编辑操作直接拒绝(edit: "deny")。这种配置适合"只读审查"场景——Agent 可以执行命令查看项目状态,但不能修改任何文件。

你还可以用一行设置全局策略:

{
  "permission": "allow"
}

这会将所有权限设为 allow(但 .env 文件保护和 external_directory 等默认安全规则依然生效)。

细粒度控制:对象语法

简单的字符串模式只能做"全有或全无"的控制。实际开发中,我们往往需要对同一类操作进行分化管理——比如允许 git status,但拒绝 git push。OpenCode 的对象语法完美支持这种需求。

Shell 命令的精细控制

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "ask",
      "git status *": "allow",
      "git diff *": "allow",
      "git log *": "allow",
      "git branch *": "allow",
      "grep *": "allow",
      "npm test *": "allow",
      "npm run dev *": "allow",
      "npm run build *": "allow",
      "git push *": "deny",
      "git commit *": "ask",
      "rm -rf *": "deny",
      "rm -r *": "deny",
      "curl *": "ask",
      "wget *": "ask"
    }
  }
}

规则匹配遵循"最后匹配获胜"原则。通常将 * 通配规则放在前面,后面跟具体的覆盖规则。上面的配置实现了:

  • 安全的 Git 只读操作(status、diff、log、branch)自动放行
  • 常见的 npm 开发命令自动放行
  • 破坏性操作(rm -rf)直接拒绝
  • Git commit 和网络请求需要人工确认
  • 其他未列出的命令默认为询问模式

注意模式末尾的 *"git status *" 可以匹配 git statusgit status --shortgit status --porcelain 等任何带后缀的命令。

文件编辑的路径级别控制

{
  "edit": {
    "*": "ask",
    "*.md": "allow",
    "packages/web/src/**/*.tsx": "allow",
    "package.json": "ask",
    "*.lock": "deny",
    ".github/workflows/*.yml": "deny"
  }
}

这个配置的策略很清晰:允许编辑文档和前端组件,修改 package.json 需要确认,锁文件和 CI 配置文件禁止修改,其余文件默认询问。

文件读取的隐私保护

{
  "read": {
    "*": "allow",
    "*.env": "deny",
    "*.env.*": "deny",
    "*.env.example": "allow",
    "*.pem": "deny",
    "*.key": "deny",
    "*.p12": "deny",
    "*.pfx": "deny",
    "*credentials*": "deny",
    "*secret*": "deny",
    ".git/config": "deny",
    "**/secrets/**": "deny",
    "**/private/**": "deny"
  }
}

这个配置加了一层敏感的"安全防线":除了默认的 .env 保护外,还禁止读取私钥文件(.pem.key)、证书文件(.p12.pfx)、凭证文件,以及 secrets/private/ 目录下的所有内容。

完整权限清单

OpenCode 支持以下权限键:

| 权限键 | 控制范围 | 支持精细控制 |
|--------|----------|:--:|
| read | 文件读取 | 是 |
| edit | 文件编辑(涵盖 write、edit、patch) | 是 |
| glob | 文件匹配搜索 | 是 |
| grep | 内容搜索 | 是 |
| bash | Shell 命令执行 | 是 |
| task | 子 Agent 调用 | 是 |
| skill | 技能加载 | 是 |
| lsp | LSP 查询 | 否 |
| question | Agent 提问 | 否 |
| webfetch | 网页抓取 | 是 |
| websearch | 网页搜索 | 是 |
| external_directory | 外部目录访问 | 是 |
| doom_loop | 死循环检测 | 否 |

其中 external_directory 是一个特殊的安全守卫——当 Agent 尝试访问工作目录之外的文件时触发,相当于一道"边界防线"。

基于 Agent 的权限分配

OpenCode 允许为不同 Agent 设置不同权限,这在多 Agent 协作时尤为重要。

JSON 配置方式

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "bash": {
      "*": "ask",
      "git *": "allow",
      "grep *": "allow"
    },
    "edit": "ask"
  },
  "agent": {
    "build": {
      "mode": "primary",
      "permission": {
        "bash": {
          "*": "allow",
          "git push *": "deny",
          "rm *": "deny"
        },
        "edit": "allow"
      }
    },
    "plan": {
      "mode": "primary",
      "permission": {
        "edit": "deny",
        "bash": "deny"
      }
    },
    "code-reviewer": {
      "description": "代码审查专用 Agent",
      "mode": "subagent",
      "temperature": 0.1,
      "permission": {
        "edit": "deny",
        "bash": {
          "*": "deny",
          "grep *": "allow",
          "git diff *": "allow",
          "git log *": "allow"
        },
        "webfetch": "deny"
      }
    }
  }
}

在这个配置中:

  • build Agent:拥有大部分操作权限,但禁止 git pushrm 系列命令
  • plan Agent:完全禁止编辑和 Shell 操作,只能分析
  • code-reviewer 子 Agent:只能运行 grep 和 Git 只读命令,不能修改文件或联网

Agent 级别的配置会与全局配置合并,Agent 配置的优先级更高。这意味着在全局设置了 edit: "ask",但在 build Agent 中设置了 edit: "allow",那么 build Agent 的文件编辑将自动放行。

Markdown Agent 配置方式

对于以 .md 文件定义的 Agent,权限可以直接写在 frontmatter 中:

---
description: 安全审查专用 Agent
mode: subagent
temperature: 0
permission:
  edit: deny
  bash:
    "*": deny
    "grep *": allow
    "git diff *": allow
    "git log *": allow
  webfetch: deny
---
你是一个安全审查 Agent。你的任务是检查代码中的安全隐患。

规则:
1. 绝不输出实际的密钥、token 或密码内容
2. 发现问题时引用文件和行号,不展示敏感值
3. 建议使用环境变量、密钥管理器等安全方案
4. 关注硬编码凭证、不安全的配置、敏感信息泄露

子 Agent 的 task 权限控制

你还可以控制哪个 Agent 可以调用哪些子 Agent:

{
  "agent": {
    "orchestrator": {
      "mode": "primary",
      "permission": {
        "task": {
          "*": "deny",
          "code-reviewer": "allow",
          "test-runner": "allow"
        }
      }
    }
  }
}

task 权限设为 deny 时,对应的子 Agent 会从 Task 工具的描述中完全移除,模型甚至不会尝试调用它。

外部目录访问控制

external_directory 是 OpenCode 的一道重要安全防线。当 Agent 需要访问项目工作目录之外的文件时,必须先过这一关:

{
  "permission": {
    "external_directory": {
      "~/.ssh": "deny",
      "~/.gnupg": "deny",
      "/etc/*": "deny",
      "/var/*": "deny",
      "/tmp/*": "allow",
      "*": "ask"
    }
  }
}

这个配置明确拒绝了 SSH 密钥和 GPG 密钥目录的访问,系统敏感目录也被阻挡在外,/tmp 目录可用作临时共享空间,其他外部路径则会触发询问。

你还可以为外部目录中的文件设置更精细的操作限制:

{
  "permission": {
    "external_directory": {
      "~/projects/personal/**": "allow"
    },
    "edit": {
      "~/projects/personal/**": "deny"
    }
  }
}

这样 Agent 可以读取个人项目中的文件作为参考,但不能修改它们。

实战:生产级安全配置

以下是一份适合大多数项目的综合安全配置:

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "read": {
      "*": "allow",
      "*.env": "deny",
      "*.env.*": "deny",
      "*.env.example": "allow",
      "*.pem": "deny",
      "*.key": "deny",
      "*.p12": "deny",
      "*.pfx": "deny",
      "*credentials*": "deny",
      "*secret*": "deny",
      ".git/config": "deny",
      "**/secrets/**": "deny",
      "**/private/**": "deny"
    },
    "edit": {
      "*": "allow",
      "*.lock": "deny",
      "package-lock.json": "deny",
      "yarn.lock": "deny",
      "pnpm-lock.yaml": "deny",
      "Cargo.lock": "deny",
      ".github/workflows/*.yml": "ask"
    },
    "bash": {
      "*": "ask",
      "git status *": "allow",
      "git diff *": "allow",
      "git log *": "allow",
      "git branch *": "allow",
      "grep *": "allow",
      "npm test *": "allow",
      "npm run lint *": "allow",
      "npm run typecheck *": "allow",
      "npm run build *": "allow",
      "git push *": "deny",
      "git push --force *": "deny",
      "rm -rf *": "deny",
      "rm -r *": "deny",
      "curl *": "ask",
      "wget *": "ask",
      "printenv *": "deny",
      "env": "deny",
      "export *": "deny"
    },
    "webfetch": "ask",
    "websearch": "ask",
    "external_directory": {
      "~/.ssh": "deny",
      "~/.gnupg": "deny",
      "/etc/*": "deny",
      "/tmp/*": "allow",
      "*": "ask"
    },
    "doom_loop": "ask"
  },
  "agent": {
    "plan": {
      "permission": {
        "edit": "deny",
        "bash": {
          "*": "deny",
          "grep *": "allow",
          "git diff *": "allow"
        },
        "webfetch": "deny"
      }
    },
    "code-reviewer": {
      "description": "代码审查 Agent — 只读",
      "mode": "subagent",
      "permission": {
        "edit": "deny",
        "bash": {
          "*": "deny",
          "grep *": "allow",
          "git diff *": "allow",
          "git log *": "allow"
        },
        "webfetch": "deny",
        "websearch": "deny"
      }
    }
  }
}

这个配置的设计思路:

严防密钥泄露:所有凭证类文件禁止读取和编辑

保护锁文件:lock 文件禁止自动修改,防止意外的依赖变更

白名单命令策略:Safe 的 Git 只读命令和开发命令自动放行,危险命令拒绝

网络操作需确认webfetchwebsearch 设为 ask,防止数据泄露

外部目录隔离:SSH 密钥和系统目录彻底拒绝,临时目录放开

Agent 分工明确:plan Agent 只能阅读思考,code-reviewer 只能审查分析

权限管理可视化

从 OpenCode v1.1.1 起,TUI 内置了权限管理对话框。打开命令面板(Ctrl+P),选择"Permissions"即可查看和管理当前的所有权限规则。对话框展示四个层级的权限:

Session(会话级):通过 always 授权临时添加的规则,重启后失效

Project(项目级):当前项目 opencode.json 中的配置

Global(全局级)~/.config/opencode/opencode.json 中的配置

Default(默认):Agent 的内置默认规则

这四个层级按 1 > 2 > 3 > 4 的优先级进行覆盖合并。你可以在对话框中直接增删改规则,修改会持久化到对应的配置文件。

运行时审批流程

当一条 ask 规则被触发时,OpenCode 会在 TUI 中弹出审批对话框,提供三种选择:

| 选择 | 效果 |
|------|------|
| once | 仅本次放行 |
| always | 当前会话内始终放行(添加临时 allow 规则) |
| reject | 拒绝此次操作 |

其中 always 是一个很实用的功能——当你信任某个模式时,选择 always 会在会话内自动添加一条 allow 规则,后续相同模式的请求会直接通过,无需反复确认。不过这条临时规则不会持久化到磁盘,重启后即失效,这是一种有意的安全设计。

--auto 命令行参数也会影响审批行为:使用 opencode --auto 启动时,所有 ask 请求会被自动以 once 方式回复。但配置中明确的 deny 规则仍然生效,不会被绕过。

总结

OpenCode 的权限管理系统是一套从简单到复杂、从全局到 Agent 逐层递进的精细控制体系。核心要点回顾:

  • 三种决策结果allow(放行)、ask(询问)、deny(拒绝)
  • 两种配置模式:字符串简写(全有或全无)和对象语法(模式匹配精细控制)
  • 规则匹配:最后匹配的规则生效,将通配规则放前面,具体规则放后面
  • 多层级覆盖:Agent 默认 < 全局配置 < Agent 配置 < 会话审批
  • 安全基线.env 文件默认拒绝读取,external_directorydoom_loop 默认询问

合理的权限配置不是要阻碍开发效率,而是为 AI 编程助手划定一个"安全活动范围"——让它在信任的区域内自由发挥,在敏感边界上主动询问,在危险地带直接止步。结合 AGENTS.md 中的安全规则声明和多 Agent 分工协作,你可以构建出一个既高效又安全的 AI 编程环境。建议从偏保守的配置开始,根据实际使用体验逐步放宽策略,找到安全与效率的最佳平衡点。