第 24 章 | permission 模式

更新于 2026/5/12
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)

第 24 章:permission 模式

学习目标

让 Claude Code 不再每步问你,但能在危险动作上自动拦。

defaultMode 三档

flowchart LR
    Default["default
每次问"] -->|友好| Annoy["✗ 烦"] AcceptEdits["acceptEdits
Edit/Write 自动
Bash 仍问"] -->|平衡| Balance["✓ 中庸"] Bypass["bypassPermissions
全部自动
仅 deny + hook 兜底"] -->|激进| Free["✓ 流畅
⚠️ 必须配 deny + hook"] style Default fill:#ffcdd2 style AcceptEdits fill:#fff9c4 style Bypass fill:#c8e6c9

→ 多 agent 项目通常用 bypass + 严格 deny——不然 dispatch 中频繁弹问,自治化形同虚设。

allow / deny 语法

Bash(<prefix>:*)           匹配命令前缀
Bash(<exact-string>)       精确匹配(少用)
Edit(<glob-pattern>)       匹配文件路径 glob
Write(<glob-pattern>)      同上

例子:

{
  "permissions": {
    "defaultMode": "bypassPermissions",
    "allow": [
      "Bash(npm:*)",
      "Bash(pytest:*)"
    ],
    "deny": [
      "Bash(sudo:*)",
      "Bash(rm -rf /:*)",
      "Edit(/etc/**)",
      "Write(/Users/amanda/.ssh/**)"
    ]
  }
}

deny 优先于 allow

flowchart TD
    Tool["Claude 想跑 X"] --> CheckDeny{命中 deny?}
    CheckDeny -->|是| Block["✗ 立刻拒"]
    CheckDeny -->|否| CheckAllow{命中 allow?}
    CheckAllow -->|是| Pass["✓ 通过"]
    CheckAllow -->|否| Mode{defaultMode?}
    Mode -->|default| Ask["弹问用户"]
    Mode -->|acceptEdits| AskOrPass["Edit/Write 通过
Bash 弹问"] Mode -->|bypass| Pass style Block fill:#ffcdd2 style Pass fill:#c8e6c9

我们 doc2video 的完整 deny 列表

"deny": [
  "Bash(sudo:*)",
  "Bash(curl * | sh:*)",
  "Bash(curl * | bash:*)",
  "Bash(wget * | sh:*)",
  "Bash(wget * | bash:*)",
  "Bash(chmod 777:*)",
  "Bash(chown:*)",
  "Bash(eval:*)",
  "Bash(:(){:|:&};:*)",

  "Edit(/etc/**)",
  "Edit(/usr/**)",
  "Edit(/System/**)",
  "Edit(/Users/amanda/.ssh/**)",
  "Edit(/Users/amanda/.aws/**)",
  "Edit(/Users/amanda/.config/gh/**)",
  "Edit(/Users/amanda/Library/**)",

  "Write(/etc/**)",
  ...
]

Bash 模式匹配的硬限制

Bash(rm:*)所有带 rm 的命令——你没法单靠 deny 做"项目内 rm 放行 / 项目外 rm 拒绝":

项目内: rm src/foo.py        ← 你想放行
项目外: rm /tmp/foo          ← 你想拦
                             
但 deny 看的只是"命令字符串前缀",两个都长一样开头
→ 必须靠 hook(Ch 25)

路径 glob 的细节

Edit(/Users/amanda/work/openspec/**)   → 项目内任意文件
Edit(/Users/amanda/.ssh/**)            → 私钥目录
Edit(*.env)                            → 任何 .env(相对路径)

→ glob 用 ** 匹配多层目录。

实战:从 default 切到 bypass 的步骤

  1. 先用 default 跑几次,看哪些操作总被询问
  2. 把"明显安全"的加进 allow
  3. 把"明显危险"的加进 deny
  4. 切换到 bypassPermissions
  5. 跑一次测试——确认不该过的被 deny 拦
  6. 跑生产任务

反模式

❌ 全开 bypass 不加任何 deny
   → 等于关掉 Claude Code 的所有安全网

❌ deny 写得太严
   → 合法操作也被拦,agent 卡死

❌ 试图用 Bash 模式做路径校验
   → 模式只看字符串,不懂语义
   → 用 hook(Ch 25)

❌ 在 settings.json 里写 token
   → 应该放 settings.local.json + env

你现在能做什么

  • 配置 bypass 模式 + 严格 deny 列表
  • 解释 deny 优先于 allow
  • 知道 Bash 模式匹配的边界(命令字符串前缀)

下一章用 PreToolUse hook 解决"路径感知"的问题。