你的钩子全绿,CI 徽章全绿,每次运行门禁都会打印一个判定结果。可它已经好几周没有真正保护过任何东西了。
![]()
这是本周读到的一份真实复盘:一道门禁在重构之后悄悄失去了判别能力——匹配器漂移了,钩子照样"运行",仪表盘照样打印判定。没人发现,因为整条流水线里没有任何环节去测量门禁到底有没有触发,只测量流水线有没有通过。
canarygate 就是为这个失效模式做的。它不测你的规则能不能挡住攻击,它测的是——线,到底接上了没有。
测的是活着,不是强度
可以把它想成带测试按钮的烟雾报警器。你按那个按钮,不是为了检查传感器能不能闻到烟,而是为了检查传感器有没有插上电。安全工具链上一直有同样的缺口:
- deny-probe(另一个工具)问的是:"我的规则能挡住攻击吗?"它找的是绕过策略的路径。
- canarygate 问的是:"线到底接上了吗?"它找的是看起来健康、但从不执行的门禁。
一条完美的拒绝规则,挂在一个死掉的钩子后面,什么都保护不了。两个检查都需要,而它们是两种不同的检查。
它怎么工作
canarygate 读取 settings.json 里的 hooks 段,对每一个(事件、匹配器、命令)三元组跑两项检查。
第一项是静态扫描:命令能不能解析出来——二进制在不在 PATH 上、脚本文件在不在?匹配器是不是合法正则?再加上轻量的脚本启发式判断:一个钩子脚本里如果任何地方都没有阻塞分支,就会被标记,因为它在结构上就不可能做出判别。
第二项是动态探针,这才是真正的证据。canarygate 合成两个事件——一个良性事件,一个在载荷里带着唯一 CANARYGATE-XXXX 毒丸标记的探针事件——把各自的 JSON 从 stdin 喂给真实的钩子命令执行(遵循 Claude Code 钩子协议:退出码 0 表示放行,2 表示拦截),然后比对两次判定。
每一个非绿结果都会附上具体证据和修复建议,因为一个没有下一步的红色判定只会制造焦虑。退出码对 CI 友好:0 表示全部存活,1 表示有门禁需要处理,2 表示致命错误。
跑起来看看
安装一行命令:pip install canarygate。然后指向你的配置文件运行,再拉一份存活报告。报告里会逐条列出每个钩子的状态和证据,比如某个钩子对良性事件和探针事件都返回了"放行",就会被标成 DEAD;某个匹配器写错了、根本匹配不上对应工具名,也会被标成 DEAD。
示例输出里,3 道门禁有 2 道需要处理,两道都属于"接上了但已死"。给出的修复建议也很具体:让钩子真正检查输入,在看到它存在的那个条件时执行拦截,然后重跑探针,直到探针被挡住;或者修正匹配器与事件注册,让探针事件真的能路由到这个钩子。
canarygate init 会搭出一个示例项目——一道活门禁、一道死门禁——你可以亲眼看着工具抓出一个、放行另一个。
它在工具链里的位置
agent-guard 是盾牌:实时监视智能体的那些钩子。deny-probe 测盾牌的强度:规则能不能挡住攻击。canarygate 审计的是盾牌架子本身:接线、匹配器,以及每个钩子是否还具备判别能力。
保护性基础设施和被保护的对象一样需要审计。一道悄悄失去判别能力的门禁,比没有门禁更糟——因为它还在打印判定,而你还信它。
代码在 GitHub 上,pip 可装,MIT 许可,只用标准库。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.