feat: add Claude-style deny-first permission overlay - #457
OldKing-lion wants to merge 3 commits into
Conversation
- 用户设置与插件可贡献 tools/paths/commands glob,命中即 Deny,压过 auto、session grant、low-risk 与 accept-edits - 插件需声明 agent.permission.deny,只能追加限制不能放宽;Plan/Goal 硬拒绝仍优先 - Settings AI 页提供 JSON 编辑,SDK 与 host 同步校验;overlay 拒绝统一返回 TOOL_DENIED - 记录 ADR 0249 / D420,并补齐中英 spec、权限矩阵与插件开发指南
Path deny now uses the same dangling-symlink ancestor resolver as execution, so auto cannot write through a workspace link onto a denied target. Path arguments are trimmed, Windows extended prefixes are stripped, and Edit MV destinations use the hashline parser. Relative ../, command whitespace, and scratch auto-allow remain denied under auto. Specs, ADR 0249, and permissionDeny copy are updated.
muzimu217
left a comment
There was a problem hiding this comment.
感谢这个 PR——deny-first 的定位(不是第四种模式、deny 在 auto 下仍然赢过 grants 与 scratch auto-allow)和几处实现细节都很到位:mv_dest_from_ops 复用真实 parser 防路径漂移、Windows \\?\/UNC/msys 路径处理、**/.env 对裸 .env 的 basename fallback,都是对的。ADR 0267/D433 与 spec en/zh 成对也齐。四点意见:
1.(会挡合并)缺 pt-BR locale。 当前 main 的 packages/i18n/src/locales/ 已是 9 个 locale(de/en/es/fr/ko/pt-BR/tr/zh-CN/zh-TW),本 PR 只改了 8 个、pt-BR 缺席。这个 PR 的 workflow 尚未被批准运行,键集全等的 catalog 测试还没机会拦——建议补上 pt-BR 再进入 review。
2.(安全文档补强)复合命令的绕过面值得一个显式反例。 spec 已多处写清 "string match, not argv"(en/zh 一致,很好),但"前缀匹配从命令串开头锚定"意味着 cd /tmp && rm -rf ~/x 不会命中 rm -rf*,rm -fr 变体也不会命中。deny 是安全边界,用户最容易误解的恰是这一点——建议 spec 的 deny 段补一个反例句("a rm -rf* rule does NOT stop cd /tmp && rm -rf …"),一段话的成本,能省掉未来一批"我明明禁了 rm"的 issue。
3.(可诊断性)DenyHit 的呈现。 命中时的 DenyHit{kind, pattern} 是否透传到工具错误 details / UI("被规则 X 拒绝"),还是坍缩成笼统的 TOOL_DENIED?用户排障需要知道命中的是哪条规则;若尚未透传,建议作为跟进项。
4.(合并顺序)与 #954 的设置 IA 冲突。 本 PR 与 #954(host 主导的自动权限审核)都往 SettingsPage/settings-search.ts 加权限入口且同域,两边合并顺序需要维护者先裁——建议在两个 PR 的描述里互相标注依赖关系,先定先后,后到的一方 rebase 成本会小很多。
Summary
Add a host-owned deny-first overlay so
auto(YOLO) is no longer unbounded.Permission modes stay
ask/accept-edits/auto. Always-deny is not a fourth mode. A match isPermissionDecision::Denyand still wins inauto, including over session grants and scratch auto-allow.Closes the gap with Claude Code: users can name tools, paths, and command prefixes that stay denied; policy plugins can only add rules.
See ADR 0267 / D433.
Behavior
Settings → AI → Permissions: JSON textarea under the mode select (
AppSettings.permissionDeny).{ "tools": ["Bash", "plugin_*"], "paths": ["**/.env", "~/.ssh/**"], "commands": ["curl", "rm -rf"] }