13Permission System

L3P1五步章 · 技术章
Why · 为什么要学
不是所有 tool 都能 auto 执行——读文件可以,删数据库要确认,发邮件要审批。permission system 是 harness 在"自动化效率"和"用户控制"之间画线的地方。设计差了用户被询问到崩溃,设计松了 agent 误删 prod 数据。这一节是 #14 Sandbox 和 #29 Prompt Injection 防御的协同前提。
1 ·核心要点

Permission system 决定每个 tool 调用走三条路径之一:

决策 行为 典型规则
allow直接执行所有 read、安全的 git 命令、特定目录 edit
ask弹 UI 让用户确认rm、未限定范围的 edit、外发请求
deny直接拒绝curl 到外部域、sudo、改 system 文件
# Claude Code permissions 配置示例
permissions:
  allow:
    - "Bash(git:*)"          # 所有 git 命令
    - "Read(*)"              # 读任意文件
    - "Edit(./src/**)"       # 只能改 src 下文件
  ask:
    - "Bash(rm:*)"           # rm 都要问
    - "Edit(/**)"            # src 之外的 edit 要问
  deny:
    - "Bash(curl:*)"         # curl 直接禁
    - "Bash(sudo:*)"         # sudo 直接禁

两阶段决策:(1) 快速分类——这个操作进 allow / ask / deny 哪个桶?(规则匹配,不调模型,延迟低);(2) 完整执行——deny 直接拒并返回 is_error,ask 弹 UI 阻塞等用户,allow 直接跑。

auto-approve list:用户在某次 ask 时勾"always allow this pattern"。这个列表要明确告诉用户"你刚授权了什么 pattern",并显示生效范围。

设计原则:默认最小权限;destructive(delete/send/publish/pay)永远 ask;高风险 pattern 即使被 auto-approve 也要 hard-coded 排除。

2 ·最小代码示例
# permission 决策伪代码
def check_permission(tool_name, tool_input, permissions, auto_approve):
    pattern = make_pattern(tool_name, tool_input)  # 如 "Bash(rm -rf /)"

    # Phase 1: 快速分类(规则匹配)
    if matches_any(pattern, permissions.deny):
        return Decision.DENY
    if matches_any(pattern, HARD_BLOCK_PATTERNS):  # 永不放行的硬底线
        return Decision.DENY
    if matches_any(pattern, permissions.allow) or pattern in auto_approve:
        return Decision.ALLOW
    if matches_any(pattern, permissions.ask):
        return Decision.ASK
    return Decision.ASK  # 默认 ask(最小权限原则)

# 关键:HARD_BLOCK_PATTERNS 不能被任何 auto-approve 覆盖
HARD_BLOCK_PATTERNS = [
    "Bash(rm -rf /)",
    "Bash(rm:* -rf:* ~)",
    "Bash(sudo:*)",
    "Edit(/etc/**)",
    "Edit(/usr/**)",
]
3 ·工程权衡

什么操作必须 ask 或 deny

  1. 不可逆 destructive(delete、drop、truncate、rm -rf)——永远 ask
  2. 外发数据(send email、post API、curl 到外网)——永远 ask,可能 deny
  3. 支付/金钱(charge、transfer、purchase)——永远 ask
  4. 权限变更(chmod、添加 user、改 share 设置)——永远 ask