权限系统
不管是 CLI、Web UI 还是 IM 渠道,每一次工具调用在真正执行前都会经过同一套权限引擎。这一页是规则 文件的参考;这套引擎在整体流程里所处的位置见Agent 循环。
~/.octo/permissions.yml
Section titled “~/.octo/permissions.yml”顶层的 key 是工具名;每个工具下面是一份有顺序的规则列表。每条规则要么是 allow:、要么是 deny:、
要么是 ask:,每个匹配子句要么是 pattern(子串匹配,给 terminal 用)、要么是 hostname
(glob 列表,给 web_fetch 用)、要么是 path(glob 列表,支持 $CWD 展开,给文件类工具用)。
匹配结果按档位而不是声明顺序判定——deny 永远压 ask,ask 永远压 allow——命中的
理由取该档位里第一条匹配的规则。所有档位都没匹配到才落到隐式的 ask。
terminal: - deny: { pattern: "rm -rf /" } - ask: { pattern: "sudo " } - allow: { pattern: "git status" } # 其他情况 => 隐式 ask
web_fetch: - deny: { hostname: ["10.*", "192.168.*", "127.*", "localhost", "*.local"] } - allow: { hostname: ["github.com", "*.github.com"] }
write_file: - deny: { path: ["**/.ssh/**", "/etc/**", "**/.env"] } # 这里没有给 $CWD/** 配 allow —— 见下面的说明在 $CWD 里面不等于对 write_file/edit_file 免检——只有 read_file 才把整个文件系统
(除了那几条针对凭据路径的 deny)当作可以无需询问直接读取的安全区。写或改任何路径,包括 cwd 内的,
只要没有规则命中都会落到隐式的 ask,所以下面的 --permission-mode 才是真正决定它是弹确认、
自动放行、还是拒绝的东西。
你写在文件里的某个工具的 key 会整体替换内置默认的那份规则列表,而不是往上面追加——默认规则里 还想保留的部分,需要自己抄一份过来。
terminal的pattern如果以/或~结尾,会做边界锚定:deny: {pattern: "rm -rf /"}会挡住清空根目录,但不会挡住rm -rf /Users/me/project。terminal的 allow 规则比deny/ask严格:命令必须(去掉首尾空白后)以这个 pattern 开头,并且不能包含任何 shell 连接用的特殊字符(; | & $ ( ) < > ```` 换行)——所以ls && rm -rf /蹭不过一条allow: "ls"的规则。hostname的 glob 里,一个*只匹配一段 DNS 标签——*.dev能匹配foo.dev,匹配不了foo.bar.dev。path的 glob 里,**可以匹配任意多段路径;$CWD会展开成引擎构造时的工作目录。permissions.yml文件不存在不算错误——直接用内置默认规则。
--permission-mode
Section titled “--permission-mode”三个取值,优先级和其他配置一样(flag > config.yml > 内置默认):
| 模式 | 对 ask 这个结论做什么 |
|---|---|
interactive(主 CLI 的默认值) |
原样传下去——由调用方弹出确认 |
auto |
直接判成 allow,不弹确认 |
strict |
直接判成 deny——评测、IM 桥接,以及其他无人值守场景用这个姿态 |
mode 只会去改隐式或显式的 ask 这一种结论——规则匹配出来的明确 allow 或 deny 永远不会被
mode 覆盖。
记住一次选择
Section titled “记住一次选择”在交互式确认里回答“总是允许”,会允许这个确切的 (工具, 输入) 组合,但只在这个会话生命周期内
有效——它从来不会被写进 permissions.yml;长期生效的策略始终需要手动改文件才算数。这个功能在三种
传输方式上表现一致(TUI/Web 弹窗里的“总是允许”选项,或者在 IM 里直接回复“总是允许”)。
write_file/edit_file 是“确切 (工具, 输入)“这条规则的例外:它们的输入里还带着新内容,每次
调用都不一样,如果按完整输入记,缓存永远不会命中第二次。这两个工具只按路径记——批准一次编辑后,
本次会话内对这个文件的后续编辑都不会再问,换一个文件还是会问一次。
一条 deny 规则永远压得过“记住”的缓存——规则先扫一遍,只有规则的结论不是 deny 时才会去看这份
记住的缓存。所以即使用户之前说了“总是允许”,之后收紧 permissions.yml 也会在下一次调用时立刻生效。
反过来,切到 strict 模式不会追溯撤销之前已经记住的允许——mode 只管未来还没被回答的确认。
这份记住的缓存会在对应会话结束时被清掉:Web UI 里删除会话时,或者 IM 里执行
/bind//unbind//new//clear 时(见Slash 命令)。
下一步:PreToolUse hook 可以在这些规则之上再加更严的门控——但永远
不能放宽,因为规则给出的明确 deny 是最终结论。