Skip to content

guard-main-checkout.sh 同样只挂 Edit|Write|NotebookEdit,本仓经 Bash 写文件(sed -i / tee / 重定向)可绕过 worktree 强制 #5790

Description

@yinlianghui

在 objectui 修 objectstack-ai/objectui#3435(PR objectstack-ai/objectui#3452)时顺带发现本仓有同一个洞,故在此单独记录。未做任何改动

现状

.claude/settings.json 里只有一条 PreToolUse 注册:

matcher: Edit|Write|NotebookEdit -> "$CLAUDE_PROJECT_DIR/.claude/hooks/guard-main-checkout.sh"

.claude/hooks/ 下也只有 guard-main-checkout.sh 一个钩子,没有任何挂在 Bash matcher 上的东西。

于是同一个写操作换成 Bash 就完全不经过钩子,在共享主 checkout 里一声不响地改文件:

sed -i 's/foo/bar/' packages/spec/src/x.ts
cat > packages/spec/src/x.ts << EOF
printf 'x' > packages/x.ts
pnpm build | tee build.log
tee / cp / mv / rm / touch 同理

而本仓 CLAUDE.md 给每个 agent 的心智模型是「A PreToolUse hook (.claude/hooks/guard-main-checkout.sh) enforces this — it blocks Edit/Write/NotebookEdit」:声明的强制范围大于实际的强制范围。多 agent 并行改同一个共享 checkout 正是 worktree-first 规则要防的事,这条路径上它没被防住。

可能做法

objectui 侧已经把这件事做完了,可以直接移植而不必重新设计:

  • .claude/hooks/guard-main-checkout-bash.sh(chore: 补上 Bash 侧的 worktree 强制,堵住 sed -i / tee / 重定向绕过主 checkout 守卫 objectui#3452)—— 挂 Bash matcher,精确优先于召回,只认 > / >> 重定向、sed -iperl -iteecpmvrmtouch;仓库判定直接沿用 guard-main-checkout.sh 自己的 git-dir 逻辑;逃生舱复用同一个 OS_ALLOW_MAIN_EDITS=1;解析不了一律 fail open;附 70 例自建 fixture 的自测矩阵。
  • 移植时需要注意本仓没有 objectui 的 guard-shared-stash.sh,所以 Bash matcher 要新建而不是往已有的数组里加。

顺带观察(是否单独立项请 triage 决定)

本仓同样没有 guard-shared-stash.sh,即 objectstack-ai/objectui#3430 记录的「stash 栈在所有 worktree 之间共享、一个 agent 的 pop 会取走另一个 agent 的条目」在本仓也完全没有防护。与上面是两个不同的缺陷,只是同一批钩子的移植工作量可以合并考虑。

证据

  • /home/user/objectstack/.claude/settings.json —— PreToolUse 下仅 Edit|Write|NotebookEdit 一条
  • /home/user/objectstack/.claude/hooks/ —— 仅 guard-main-checkout.sh
  • /home/user/objectstack/CLAUDE.md —— 声明钩子强制 worktree-first

未搜到已有的同类 open issue(按 guard-main-checkout / Bash / worktree / .claude/settings.json 等关键词搜过)。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions