权限规则
用细粒度的 allow / ask / deny 规则、权限模式与多层 settings 精准约束 CodeBuddy Code 能做什么。规则可以提交到版本库与团队共享,也可以由开发者本地覆盖。
权限系统概览
CodeBuddy Code 用一套分层评估机制平衡能力与安全。每次工具调用前都会按下述 8 个 Phase 顺序判定:
| Phase | 检查项 | 命中后行为 |
|---|---|---|
| 1 | Deny 规则 | 立刻拒绝,最高优先级 |
| 2 | 可信 Allow 规则(user / cli / flag / session / policy / 信任目录下的 project / --allowedTools) | 立刻放行,可越过命令安全检查 |
| 3 | 命令安全检查(仅交互式) | 高危 / 危险命令强制询问 |
| 4 | Ask 规则 | 强制询问 |
| 5 | Bypass 模式短路 | bypassPermissions 模式直接放行;disableBypassPermissionsMode 已禁用时降级 default |
| 6 | 不可信 Allow 规则(不在信任目录的 project / local,以及 command / sandbox 来源) | 放行,但不能越过命令安全检查 |
| 7 | 权限模式策略 | 按当前 权限模式 决定是否需要审批 |
| 8 | dontAsk / async agent 兜底 | print / 异步代理场景把 ask 转成 deny 避免死锁 |
要点:deny 永远优先,且分"可信 / 不可信" allow 两层 —— 项目根目录被列入信任目录前,
.codebuddy/settings.json的 allow 规则不能越过命令安全门。目的是防止恶意仓库把自己的 settings 推到团队 PR 时绕过本地安全保护。
读类工具(Read / Grep / Glob 等)默认在信任目录内不弹审批,编辑类与 Bash 一律走完整 Phase 链。
规则的三种行为
permissions 对象下三个数组对应三种行为:
json
{
"permissions": {
"allow": ["Bash(npm test)", "Read(/tmp/data/**)"],
"ask": ["WebFetch"],
"deny": ["Bash(rm -rf *)", "Edit(.git/**)"]
}
}allow:CodeBuddy 可使用且无需弹审批ask:每次使用都弹审批deny:绝不能使用
在哪里管理规则
/permissions 命令
会话里输入 /permissions 打开权限管理面板,可以查看当前所有 allow / ask / deny 规则、它们来自哪一层 settings,并临时增删(写到 user / project 或 project-local 任一作用域)。
弹窗里勾选 "Yes, don't ask again" 时,CodeBuddy 会把当前命令对应的最稳前缀写入对应作用域 settings 的 allow 数组。
CLI 启动参数
| 参数 | 作用 |
|---|---|
--allowedTools <tools...> | 进程级临时 allow 规则。空格或逗号分隔。例:--allowedTools "Bash(git:*) Edit" |
--disallowedTools <tools...> | 进程级临时 deny 规则。同上 |
--add-dir <path> | 把额外目录加入信任目录范围(影响 Read 是否需要弹询问) |
-y / --dangerously-skip-permissions | 等价于 --permission-mode bypassPermissions |
配置文件
详见 Settings 配置。CodeBuddy 按这 4 个作用域合并:
| 作用域 | 路径 |
|---|---|
| user | ~/.codebuddy/settings.json |
| project | <repo>/.codebuddy/settings.json(提交进 git) |
| project-local | <repo>/.codebuddy/settings.local.json(不进 git,本地覆盖) |
| cliArg / flagSettings / session / policySettings | 进程态,不落盘 |
规则语法
规则形态:Tool 或 Tool(specifier)。
整体匹配某个工具
去掉括号匹配工具的所有调用:
| 规则 | 含义 |
|---|---|
Bash | 所有 Bash 命令 |
WebFetch | 所有 web 抓取 |
Read | 所有文件读 |
Edit | 所有文件编辑 |
* 也可以单独作为规则,相当于全匹配通配。
加 specifier 做细粒度
在括号里写参数:
| 规则 | 匹配 |
|---|---|
Bash(npm run build) | 精确匹配 npm run build |
Bash(npm:*) 或 Bash(npm *) | npm 开头的所有命令 |
Read(./.env) | 当前目录的 .env |
Edit(/src/**/*.ts) | 项目根下 src/**/*.ts |
Read(~/.zshrc) | 用户目录的 .zshrc |
Read(//tmp/scratch.txt) | 文件系统绝对路径 /tmp/scratch.txt |
WebFetch(domain:example.com) | 抓取 example.com |
mcp__puppeteer__navigate | MCP 工具 puppeteer 服务的 navigate |
Agent(Explore) | 子代理 Explore |
工具特定规则
Bash
Bash 规则支持三种语法:
| 语法 | 含义 | 示例 |
|---|---|---|
| 精确匹配 | pattern 完全等于命令 | Bash(npm run build) 仅匹配 npm run build |
:* 前缀 | pattern 末尾 :* → 匹配命令第一个词 / 多词前缀 | Bash(git:*) 匹配 git status / git push origin main |
| 通配符 | pattern 含 * 时按 bash glob 模式匹配(* 可跨 /) | Bash(npm run *) 匹配 npm run build;Bash(ls *) 匹配 ls -al /tmp/x |
通配符模式刻意让
*能跨越/—— 否则ls *无法匹配ls -al /xxx,这是用户最常踩的坑。
复合命令
CodeBuddy 会解析 shell 操作符 && / || / ; / |,对每个子命令独立判定:
- deny / ask 规则:任一子命令命中即触发
- allow 规则:要求所有子命令都命中才放行 —— 一个命中、一个不命中的复合命令仍会询问,避免攻击者把危险命令藏在被允许的命令旁边
举例:
text
allow: ["Bash(git:*)"]
git status → 允许
git status && rm * → 询问(rm * 不在 allow 内,需所有子命令都命中)
git status; rm * → 询问(同上)重定向
包含 > / < / >> / << / &> 的命令在 allow 规则下要求精确匹配,通配符规则不生效。
Read / Edit / Write
文件类规则按 glob 匹配,并做了三层路径归一:
| pattern | 解释 | 示例 |
|---|---|---|
//path | 文件系统绝对路径 | Read(//etc/hosts) |
~/path | 用户目录起 | Read(~/.zshrc) |
/path | 项目根起 | Edit(/src/**/*.ts) |
path 或 ./path | 当前工作目录起 | Read(.env) |
匹配开关:允许点开头、不区分大小写、裸文件名可匹配任意深度。
注意:
Edit(.git/**)之类的 deny 规则会阻挡所有走 Edit / Write / NotebookEdit 的尝试;但不阻挡通过 Bash 跑python -c 'open(".git/config", "w")...'这类间接路径 —— 操作系统级保护需要靠 Bash 沙箱- Read 规则同样会被部分 Bash 文件读命令(
cat、head、tail等)拦截解析
WebFetch
text
WebFetch # 任何 URL
WebFetch(domain:example.com) # 仅 example.com 及子域支持 domain: 前缀做主机名匹配(含子域)。
MCP 工具
MCP 工具命名格式:mcp__<server>__<tool>。规则三种粒度:
| 规则 | 匹配 |
|---|---|
mcp__puppeteer | 整个 puppeteer server 的所有工具 |
mcp__puppeteer__* | 同上(通配符写法) |
mcp__puppeteer__navigate | 仅 navigate 工具 |
工具名以 mcp__ 开头时按 MCP 规则匹配。
Agent(子代理)
json
{
"permissions": {
"deny": ["Agent(Explore)", "Agent(Plan)"]
}
}也可用 CLI flag:
bash
codebuddy --disallowedTools "Agent(Explore) Agent(Plan)"被 deny 后主代理调起 Agent 工具时该 subagent_type 会被拒。
Skill
json
{
"permissions": {
"deny": ["Skill(dangerous-skill-name)"]
}
}Skill 规则必须是精确匹配,不支持通配符。
信任目录
CodeBuddy 默认认为只有当前工作目录是受信任的。Read 工具在受信目录内放行,受信外询问;Edit / Bash 永远走完整审批(除非有 allow 规则或处于宽松模式)。
扩大信任范围的几种方式:
| 方式 | 持久度 |
|---|---|
--add-dir <path> 启动参数 | 进程级 |
会话内 /add-dir 命令 | 会话级 |
permissions.additionalDirectories 配置项 | 持久化 |
permissions.trustedDirectories 配置项 | 持久化 |
最终生效的信任目录 = 工作区根 + settings.trustedDirectories + 启动时 --add-dir / 会话内 /add-dir 添加的目录。
--add-dir和permissions.additionalDirectories都只授予文件访问权,不会让 CodeBuddy 加载这些目录里的.codebuddy/配置(agents / hooks / settings 等都仍以启动目录的为准)。
项目目录信任开关
仓库目录是否被你"显式信任"还会影响 allow 规则的可信级别。当目录未被信任时:
<repo>/.codebuddy/settings.json与.codebuddy/settings.local.json里的allow规则会被归到不可信层(Phase 6),不能越过命令安全检查- 用户在交互界面确认信任后,项目级规则会被提升到 Phase 2 可信层
目的是缓解仓库被克隆后立即跑产生的横向风险。
受保护文件 / 路径
任意模式下,CodeBuddy 都会对一组关键路径加额外保护(与 权限模式 一致):
- 仓库自身:
.git、.gitconfig、.gitmodules - shell 配置:
.bashrc/.zshrc/.envrc等 - 包管理:
.npmrc/.yarnrc/bunfig.toml等 - IDE 工具:
.vscode/.idea/.husky/.devcontainer - CodeBuddy 自身:
.codebuddy(除.codebuddy/worktrees) - MCP / 配置:
.mcp.json/.codebuddy.json
bypassPermissions 模式仍然会让其中绝大部分通过,但 rm -rf / / rm -rf ~ 这类"灾难性命令"会被强制询问。
用 Hooks 扩展权限
Hooks 钩子系统 的 PreToolUse 钩子会在权限弹审批之前运行,可以编程式 allow / deny / 改写输入。
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "/path/to/bash-policy.sh" }]
}
]
}
}钩子退出码语义:
| 退出码 | 行为 |
|---|---|
0 + JSON 决策 | 按 JSON 里的 permissionDecision(allow / ask / deny)执行 |
2 | 阻断(stderr 内容回填给模型) |
| 其他非 0 | 非阻断错误(提示但放行) |
注意:
- deny / ask 规则始终先于钩子生效。钩子返回
"allow"不能越过 settings 里的 deny - 但阻断式钩子(exit code 2)能在 Phase 1 之前短路 allow 规则,所以可以"先放行 Bash 全部,但用钩子单独拦几条特定命令"
与沙箱的协作
权限规则与 Bash 沙箱 是互补层:
- 规则层:约束 CodeBuddy "想不想用"某工具或访问某路径
- 沙箱层:约束 Bash 子进程在 OS 层"能不能真的访问"某资源
防御纵深的典型组合:
deny规则阻挡 CodeBuddy 主动尝试受限工具- 沙箱阻挡所有 Bash 子进程触达白名单外的文件 / 网络 —— 即使 prompt injection 让 CodeBuddy 想绕也做不到
- WebFetch 的
domain:allow 规则与沙箱allowedDomains都生效,最终边界取交集
Settings 优先级
权限规则继承通用 Settings 优先级:
flagSettings / cliArg / session > userSettings > policySettings >
projectSettings > localSettings > command/sandbox 来源但评估顺序比 settings 优先级更重要:
deny数组从所有作用域合并,任一作用域 deny 即拒allow数组按"可信 / 不可信"分两次合并:可信合并里 user / cli / flag / session / policy 永远在;project / local 仅在目录被信任时算可信disableBypassPermissionsMode在 user / project / local / CLI 启动参数四层任一为"disable"即生效
示例配置
最小化信任:只允许 npm 测试 + 读项目内文件
json
{
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm test)",
"Bash(npm run lint)",
"Read(/src/**)",
"Read(/test/**)"
],
"deny": [
"Bash(rm:*)",
"Bash(curl:*)",
"Bash(wget:*)",
"Edit(.git/**)",
"Edit(/.codebuddy/**)"
]
}
}CI / 流水线场景:跳过审批 + 强 deny
json
{
"permissions": {
"defaultMode": "bypassPermissions",
"deny": [
"Bash(rm -rf /:*)",
"Bash(sudo:*)",
"Bash(curl * -o /etc/*)",
"WebFetch(domain:internal-corp.example)"
]
}
}团队共享 + 个人放宽
<repo>/.codebuddy/settings.json(提交进 git):
json
{
"permissions": {
"deny": ["Bash(rm:*)", "Edit(.git/**)"]
}
}~/.codebuddy/settings.json(用户级,私有):
json
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": ["Bash(git:*)", "Bash(npm:*)"]
}
}相关资源
- 权限模式:default / acceptEdits / plan / bypassPermissions / delegate 等模式
- Settings 配置:完整配置字段、作用域与合并规则
- Hooks 钩子系统:用钩子做编程式权限决策
- Bash 沙箱化:Bash 命令的 OS 级隔离
- CLI 参考:
--allowedTools/--disallowedTools/--add-dir等启动参数 - 安全:整体安全模型与最佳实践
- IAM 身份与访问:组织级身份认证与权限控制