Files
docker_practice/.github/workflows/identity-guard.yaml
T
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

138 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Identity Guard
# 拒绝把 AI 助手写成提交作者/提交者或写进 Co-authored-by 尾注
# 本地 .git/hooks 不随仓库分发云端会话推上来的提交不受其保护
# 因此这道检查必须放在服务端
on:
push:
# 'branches: [**]' 覆盖所有分支且天然排除 tag
# 注意不能写成只有 tags-ignoreGitHub 的规则是"只给了 tag 过滤器就只跑 tag"
# 于是 tags-ignore: ['**'] 等于"只跑 tag,但忽略所有 tag" —— 工作流永不触发
branches: ['**']
pull_request:
workflow_dispatch:
permissions: {}
jobs:
check-commit-identity:
permissions:
contents: read
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Reject AI assistant identities and co-author trailers
env:
EVENT_NAME: ${{ github.event_name }}
BEFORE_SHA: ${{ github.event.before }}
HEAD_SHA: ${{ github.sha }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
ZERO=0000000000000000000000000000000000000000
US=$'\037' # 用不可能出现在姓名/邮箱里的 unit separator 作分隔符
# 确定扫描范围三种情况
# 1. pull_requestbase..head只看本 PR 新增的提交
# 2. push before 指向一个真实存在的提交before..head
# 3. 其余新建分支 before 0force-push before 不可达
# workflow_dispatch):退化为全量审计扫描 HEAD 的完整历史
if [ "$EVENT_NAME" = "pull_request" ]; then
RANGE="${PR_BASE_SHA}..${PR_HEAD_SHA}"
elif [ "$EVENT_NAME" = "push" ] \
&& [ -n "${BEFORE_SHA:-}" ] \
&& [ "$BEFORE_SHA" != "$ZERO" ] \
&& git cat-file -e "${BEFORE_SHA}^{commit}" 2>/dev/null; then
RANGE="${BEFORE_SHA}..${HEAD_SHA}"
else
RANGE="$HEAD_SHA"
fi
echo "Scanning range: ${RANGE}"
# 只有"确实没有 head 提交"例如删除分支的 push才允许放行
# 其余任何解析不出范围的情况一律 fail closed不能静默通过
if [ -z "${HEAD_SHA:-}" ] || [ "$HEAD_SHA" = "$ZERO" ]; then
echo "No head commit (branch deletion?); nothing to check."
exit 0
fi
if ! COMMITS="$(git rev-list "$RANGE" 2>&1)"; then
echo "::error::cannot resolve commit range ${RANGE}: ${COMMITS}"
exit 1
fi
COUNT="$(printf '%s' "$COMMITS" | grep -c . || true)"
echo "Commits in range: ${COUNT}"
if [ "$COUNT" -eq 0 ]; then
echo "No commits to check."
exit 0
fi
# 身份判定刻意收窄避免误伤
# - 邮箱在 AI 厂商域名下含子域
# - 姓名恰好等于助手名因此真人 "Claude Dubois" 不受影响
# 正文里出现 Claude/Anthropic 是完全合法的本仓库群里有专讲 Claude
# 的书),所以只检查身份字段与 Co-authored-by 尾注绝不扫描自由文本
BAD_EMAIL='@([a-z0-9.-]+\.)?(anthropic|openai)\.com$'
BAD_NAME='^(claude([ ._-]?code)?|codex|chatgpt|copilot|anthropic|openai)(\[bot\])?$'
BAD_TRAILER='^[[:space:]]*co-authored-by:.*(claude|anthropic|codex|copilot|openai)'
# 粗筛BAD_EMAIL BAD_NAME 命中的行必然含下列词之一
# 因此它是二者的超集用来跳过绝大多数干净提交不会漏判
BAD_ANY='(claude|anthropic|codex|chatgpt|copilot|openai)'
failed=0
# 身份检查命令替换先落地set -e 才能捕获 git 失败
# while 循环用 here-string 喂数据避免管道子 shell 吞掉 failed 赋值
IDENTS="$(git log --format="%H${US}%an${US}%ae${US}%cn${US}%ce" "$RANGE")"
# here-string 而不是管道set -o pipefail grep -q 命中即退出会让
# 左侧进程收到 SIGPIPE整条管道返回非 0if 就会跳过检查——
# 而且只在输入大到写不进管道缓冲区时才发生是典型的隐性漏判
if grep -qiE "$BAD_ANY" <<< "$IDENTS"; then
while IFS="$US" read -r sha an ae cn ce; do
[ -n "$sha" ] || continue
for role in author committer; do
if [ "$role" = author ]; then name="$an"; mail="$ae"; else name="$cn"; mail="$ce"; fi
lname="$(printf '%s' "$name" | tr '[:upper:]' '[:lower:]')"
lmail="$(printf '%s' "$mail" | tr '[:upper:]' '[:lower:]')"
if printf '%s' "$lmail" | grep -qE "$BAD_EMAIL" \
|| printf '%s' "$lname" | grep -qE "$BAD_NAME"; then
echo "::error::${sha} ${role} identity is an AI assistant: ${name} <${mail}>"
failed=1
fi
done
done <<< "$IDENTS"
fi
# Co-authored-by 尾注检查行首锚定并要求冒号避免匹配正文叙述)。
# 先用一次 git log 流式扫全部正文只有确实命中时才逐个提交定位
# 否则全量审计要为每个提交起一个 git 子进程1500+ 提交约 50 )。
BODIES="$(git log --format='%B' "$RANGE")"
if grep -qiE "$BAD_TRAILER" <<< "$BODIES"; then
while read -r sha; do
[ -n "$sha" ] || continue
body="$(git log -1 --format='%B' "$sha")"
if printf '%s' "$body" | grep -qiE "$BAD_TRAILER"; then
echo "::error::${sha} has a Co-authored-by trailer referencing an AI assistant"
printf '%s' "$body" | grep -iE "$BAD_TRAILER" | sed 's/^/ /'
failed=1
fi
done <<< "$COMMITS"
fi
if [ "$failed" -ne 0 ]; then
echo ""
echo "AI assistant attribution found in the commits above."
echo "Rewrite them before pushing, e.g.:"
echo " git rebase -i --exec 'git commit --amend --no-edit --reset-author' <base>"
exit 1
fi
echo "OK: no AI assistant identity or Co-authored-by trailer in ${COUNT} commit(s)."