Commit Graph
5 Commits
Author SHA1 Message Date
yeasy 1e56295251 fix(ci): close two silent false negatives in Identity Guard
An audit found the guard could miss commits it exists to catch.

1. SIGPIPE. Three inner checks used `printf ... | grep -q` under
   `set -euo pipefail`. When grep -q matches early it exits, printf dies of
   SIGPIPE, pipefail turns the pipeline non-zero, the `if` goes false, and the
   offending commit is silently not reported — the guard then prints its
   success line. This file already documents the hazard in a comment and had
   fixed it for the two outer pre-filters; the three inner ones were left as
   pipes. Now here-strings, like the rest.

   Demonstrated on a synthetic revert-style commit (an AI trailer quoted near
   the top, then a 200KB body): the pipe form MISSES it, the here-string form
   detects it. A trailer in the conventional last position happens to survive
   the pipe form, because grep must read to the end before matching — which is
   why this never showed up in practice.

2. `chatgpt` was in BAD_NAME and BAD_ANY but not BAD_TRAILER, so a
   Co-authored-by naming ChatGPT with an email outside anthropic.com/openai.com
   was not caught. Confirmed by test, then added.

Verified before pushing this time: the amended script flags an AI-authored
commit, a large-body early trailer, and a ChatGPT trailer, and scans
claude_guide's full 345-commit history with zero false positives — that repo
has 46 commits with Claude or Anthropic in the subject, none of which are
identity or trailer hits.
2026-07-23 13:13:39 -07:00
yeasy a42f94faad ci: add timeout-minutes to Identity Guard
harness_engineering_guide 的 lab/tests/unit/test_project_configuration.py 要求
每个工作流都写 timeout-minutes,我漏了,导致该仓库 CI 变红。

漏检原因值得记一笔:我本地批量跑测试时用的是 `ls tests/test_*.py`,
而 harness 的测试在 lab/tests/ 下、且用 pytest,这个 glob 一个都没匹配到,
于是它被静默报成"OK"。应当按各仓库 ci.yaml 里真正的测试命令来跑。

timeout-minutes 本身也是好实践:避免作业异常时空转到默认上限。
统一给 14 个仓库都加上,与该测试的其余约束(SHA 固定、禁 continue-on-error、
checkout 不持久化凭据)保持一致。
2026-07-22 16:04:50 -07:00
yeasy 38c89065b6 ci: fix Identity Guard trigger — it was never actually running
上一版给 push 只写了 tags-ignore: ['**'],本意是让发布 tag 不再触发一次
重复的全量审计。但 GitHub 的过滤规则是"只给了 tag 过滤器,就只在 tag 上跑",
因此这条配置的真实含义变成"只跑 tag,但忽略所有 tag" —— 工作流一次都不会触发。

症状很有迷惑性:工作流在 API 里状态是 active、名字也正常显示,
只是 runs 数恒为 0,同一次推送里 CI 和 Preview 都正常跑。
改为 branches: ['**'],覆盖全部分支且天然排除 tag,达到原本的意图。

教训记一句:光看"工作流已注册/active"不能算验证,必须确认它真的产生了 run。
2026-07-22 15:37:50 -07:00
yeasy 3781d9c382 ci: fix a latent false negative and cut Identity Guard runtime 50s to 1s
两处都是本地实测发现的,不是推测。

1) 漏判(正确性):尾注预筛写成 `git log --format=%B "$RANGE" | grep -qiE`,
   在 `set -o pipefail` 下 grep -q 命中即退出,左侧 git log 收到 SIGPIPE,
   整条管道返回非 0,if 判定为"没命中"从而跳过整个尾注检查。
   实测:沙箱里 8 条应报错误只报出 6 条,两个带 AI 尾注的提交被静默放过。
   改为 here-string(不再有管道),身份预筛同样改掉以杜绝这一类问题。

2) 性能:全量审计路径(新建分支推送、workflow_dispatch)原先为每个提交
   各起一个 git 子进程,docker_practice 1,592 个提交实测 50 秒。
   现在先用一次 git log 流式预筛,只有命中时才逐个提交定位;
   同一仓库实测降到 1 秒,且不改变任何判定结果。

回归验证:被删分支的真实 4 个提交在 push / pull_request / 新建分支三种
形态下仍全部拦下;专门构造的 2,502 提交仓库(身份流 258KB,远超管道缓冲区)
中埋在末尾的 AI 提交能被检出;14 个仓库完整历史仍然零误报;
范围解析失败仍 fail closed,删除分支仍正确放行。
2026-07-22 15:34:52 -07:00
yeasy f82e13017d ci: add Identity Guard rejecting AI-assistant commit attribution
起因:blockchain_guide 上曾有一个 claude/novel-content-extraction-r0wys3
分支,4 个提交的 author 和 committer 都是 Claude <noreply@anthropic.com>
(内容还是与本书无关的小说抓取脚本)。分支已删除,但暴露出一个缺口:
既有的 .git/hooks/commit-msg 只查提交信息里的 Co-authored-by 尾注,
查不到身份字段;而且本地钩子不随仓库分发,那 4 个提交来自云端会话,
根本不经过本地钩子。

因此把闸门放到服务端:本工作流在 push 与 pull_request 上扫描本次新增
提交的 author/committer 身份与 Co-authored-by 尾注,命中即失败。
本地另配 pre-commit(拦当前身份)与 pre-push(拦 cherry-pick/rebase
带进来的外来提交)作为纵深防御,二者不入库。

判定刻意收窄,避免误伤本仓库群里大量讨论 Claude/Codex 的正文:
只检查身份字段与行首锚定的 Co-authored-by 尾注,绝不扫描自由文本;
姓名要求全等("Claude Dubois" 这样的真人不受影响),邮箱按厂商域名
(含子域)匹配,并覆盖 claude[bot] 这类 GitHub App 身份。

已验证:
- 用被删分支的真实 4 个提交做回归,push / pull_request / 新建分支
  三种到达形态全部拦下;
- 全部 14 个仓库的完整历史(5,715 个提交,含 docker_practice 1,591
  个多人历史与 claude_guide 339 个满是 Claude 的提交)零误报;
- dependabot 的 Co-authored-by、真人 Claude Dubois、正文提到
  co-authored-by 但非尾注的提交,均正确放行;
- 范围解析不出来时 fail closed,只有确实没有 head 提交(删分支)才放行;
- tags-ignore 避免发布 tag 触发一次重复的全量审计。
2026-07-22 15:24:38 -07:00