MySQL 自定义函数应用场景全解析实用指南
2026-10-02
2026-10-02 0
在项目中评估nk-git-guardrail-hook,可以先看清用途边界:在强制推送、批量删除、repo-gone-public 和curl 之前停止|嘘;七个提示中有五个指出了规则背后的事件。对软件开发任务来说,依赖、接口和异常处理往往比主路径更影响采用往往决定它能否落地,不能只用安装成功来判断。我的评估方法是在隔离分支完成一个可回滚的小任务,然后检查安装步骤、接口契约、测试结果和错误信息是否与文档一致。它对需要可检查开发流程而非单次演示的工程师更有价值,但正式采用前仍要复查许可证、近期提交和问题区回应。

名称:nk-git-guardrail-hook 描述:“Claude Code 的一个 PreToolUse 钩子在七个危险的 git 和 shell 命令之前停止 - 强制推送、共享结账中的 git add -A、公开存储库、在远程后面推送、记录批量删除的推送、主文件夹或文件系统根目录上的递归 rm、直接在 shell 中运行的下载。所有七个命令都在没有配置文件的情况下运行。提示符说明了危险:对于前五个命令,规则背后的真实事件;对于最后两个,为什么该步骤是不可逆转的或危险的。当多个代理会话代表您推送时,或者当您不断单击相同的确认时(然后重播真实命令历史记录以缩小或强化规则),仅拒绝代理可以修复其自己的命令的位置,如果钩子本身中断,则失败打开。 许可证:MIT 元数据: 出处:自己的实践(2026-08 至 2026-09);没有外部来源 版本:0.1.6
Git护栏挂钩
文档中的红线由任何记得它的人强制执行。此钩子移动七 将它们放入每个 Bash 命令都会经过的地方,其提示符会说明危险所在:规则 1-5 说出他们背后的真实事件;规则6和7没有记录事件,它们的提示说明了为什么该步骤 是不可逆转的或危险的。
路径。 此技能中的命令以
${…SKILL_DIR}开头:此技能自己的文件夹,即包含此 SKILL.md 的文件夹。 Claude Code 会填写该内容。如果您的代理显示所写的占位符(Codex、Cursor、Gemini CLI 等),请在运行命令之前将其替换为该文件夹的绝对路径。如果放任不管,它就会扩展为空,路径就会断裂。
安装(两分钟)
~/.claude/settings.json 中:
python3 ${CLAUDE_SKILL_DIR}/scripts/guardrail.py --settings-snippet~/.config/guardrail/config.json 的可选配置:
{"protected_roots": ["~/projects"], "add_all": "deny", "mass_delete_min": 20, "mass_delete_ratio": 3}
protected_roots 将您自己的项目文件夹添加到规则 6(这些根目录下最多两层的路径)。规则的
内置目标(主文件夹、文件系统根目录、当前文件夹)不需要配置。python3 ${CLAUDE_SKILL_DIR}/scripts/guardrail.py --try "git push --force" 打印 ask 及其原因。python3 ${CLAUDE_SKILL_DIR}/scripts/guardrail.py --selftest(通过真实入口点的 110 个命令;询问、拒绝和允许每个命令都有示例,规则 4 和 5 针对真实临时存储库运行,并且显示每个规则在没有配置文件的情况下进行回答:摘要行的最后一个单词是计数,7 of 7 rules on with no config file)。规则
| # | 命令形状 | 决定 | 为什么存在 |
|---|---|---|---|
| 1 | git push --force / -f / + 参考规范,例如 +main 或 +HEAD:main(不是 --force-with-lease,带或不带 --force-if-includes) |
问 | 事件:一个共享分支的历史被重写,而另一个会话正在其上重新建立基础 |
| 2 | git add -A / . / --all / * / ./ / :/ |
拒绝(可配置) | 事件:在一次结账中有多个会话,另一个会话的半写文件被扫入提交 |
| 3 | gh repo create/edit --public、--visibility public 或 --visibility=public、gh api … private=false 或 visibility=public |
问 | 事件:由于没有人询问,内部页面被公开;出版出版所有历史 |
| 4 | git push,而分支位于原点后面(运行真正的 fetch) |
问 | 事件:在仅存在于远程的工作上构建并部署了过时的本地副本 |
| 5 | git push 其待处理的提交删除了 ≥ 20 个文件,并且比它们添加的文件多了 3 倍(自原始以来累计) |
问 | 事件:一个中断的稀疏克隆留下了一个空的工作树;该提交记录了 1,000 多个删除; add/commit/push 全部退出 0 |
| 6 | 主文件夹(~、$HOME、 "${HOME:?}"、~/ 或 cd ~ 之后的 )、文件系统根目录、home 上方的文件夹或 . / ..;配置中包含 protected_roots,也在这些根之一下的路径 ≤ 2 级上 |
问 | 这里没有记录的事件:该步骤是不可逆转的;暂存目录和临时克隆故意不受到保护 |
| 7 | curl/wget 通过管道传输到 sh/bash/python3/node…,或通过 shell 参数运行:sh -c "$(curl …)"、bash <(curl …)、eval "$(curl …)" |
问 | 没有记录的事件:它运行没有人读过的下载代码,这是“安装脚本”攻击链的结束步骤;保存、阅读、报告 |
规则 4 和 5 解析命令所作用的存储库 (git -C > 最后一个 cd > cwd),因为
规则 5 背后的事件发生在临时克隆中,而基于 CWD 的检查正是盲目的。
设计规则(为什么这样构建)
git add -A 被拒绝,并修复了
原因(git add -- ),因为人类在一周内点击“允许”169 次是转移到
错误的人;代理可以纠正自己的命令。rm 和 curl | sh 是例外:都没有记录事件
在这里,他们的提示说明了危险所在 - rm 无法撤消; 卷曲 | sh 运行没有人读过的代码。bash <,... | sh, eval, ssh 主机 <)。
带引号的字符串将被忽略,但引号内的 $(…) 会被保留 - 它会运行 - 并且带引号的字符串也会被传递给
一个外壳(bash -c '…'、sh -lc "…"、eval '…')。引用的单个单词保留规则 3 和 6 的文本,因此
"$HOME" 和 --visibility "public" 的读法如其名称所示。 ;、&&、|,换行符);中的一条路径
接下来的命令就不怪这个rm了。代价是:通过变量传递的目标是不可见的。根据真实历史进行调整
当同样的提示不断出现时:python3 ${CLAUDE_SKILL_DIR}/scripts/replay.py --days 7 feeds every
Bash 命令您的会话通过钩子运行(包括子代理)并打印决策分布
每个原因都有样本。在规则更改之前和之后运行它;差异就是证据。两个结果:
误报→缩小规则范围;代理可以自行修复的真阳性 → 否认修复
原因。唯一值得保留的提示是人类应该实际决定的提示。
边界(它看不到的东西)
git reset --hard、git clean -f、git checkout -- . 和 git branch -D
被允许:这里没有任何事件发生。 cc-安全网
阻止这些以及更多,以吸引更多代理;两人可以并肩奔跑。. 或
..。它不会询问 home 内的文件夹 (~/Documents)、普通文件夹中的裸 * 或项目
文件夹,除非 protected_roots 将其命名。 cc-safety-net 询问工作目录之外的每个递归 rm。$HOME 和 $PWD (R=~/projects/app; rm -rf $R) 以外的变量传递的目标以及馈送至的定界符主体
python/node that shell out. Real isolation is a sandbox; this hook removes the most common step.curl -o i.sh …; sh i.sh) 是两个
普通命令,与 python3 -c "$(curl …)" 不匹配(仅 shell 形式匹配)。find ~ -delete、xargs rm、cd。出处
自己的实践,2026-08 至 2026-09。在审查作者自己的设置后发现,一开始有六条规则 执法是其最薄弱的部分——有很多红线,但没有任何执行力。然后使用以下方法缩小或强化规则: 真实命令历史记录的 7 天重播(约 7,500 个命令):一条规则在执行后从询问变为拒绝 169提示无真阳性;一条没有任何事件发生的规则被删除,另一条则被删除 直到它的“卷曲” | sh`线,遵守规则7,没有发生任何事件。没有外部来源。