-
Notifications
You must be signed in to change notification settings - Fork 23
100 lines (90 loc) · 3.66 KB
/
Copy pathno-ai-coauthor.yml
File metadata and controls
100 lines (90 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
name: no-ai-coauthor
# 阻塞含 AI Co-Authored-By trailer 或 AI author email 的 commit 进入 main。
# 配合 branch protection 把本 workflow 加进 required status checks 后,
# 任何含 AI 署名的 PR 都无法 squash merge。
on:
pull_request:
branches: [main]
# `ready_for_review` 让 draft → ready 触发;`synchronize` 在 draft 仍 fire,
# 下面 job-level `if` 把 draft job skip(skip = pass,不卡 required check)。
types: [opened, synchronize, reopened, ready_for_review]
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
jobs:
no-ai-coauthor:
# draft PR 期间 skip;push/dispatch/non-draft PR 正常跑。
if: github.event_name != 'pull_request' || github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Determine commit range
id: range
env:
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PUSH_BEFORE: ${{ github.event.before }}
PUSH_AFTER: ${{ github.sha }}
run: |
set -eu
if [ -n "${PR_HEAD_SHA:-}" ]; then
BASE="$PR_BASE_SHA"
HEAD="$PR_HEAD_SHA"
else
BASE="$PUSH_BEFORE"
HEAD="$PUSH_AFTER"
fi
if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
echo "range=$HEAD~1..$HEAD" >> "$GITHUB_OUTPUT"
else
echo "range=$BASE..$HEAD" >> "$GITHUB_OUTPUT"
fi
- name: Scan commits for AI co-author / email
env:
RANGE: ${{ steps.range.outputs.range }}
run: |
set -eu
echo "Scanning commits in range: $RANGE"
COMMITS=$(git log --format='%H' "$RANGE")
if [ -z "$COMMITS" ]; then
echo "No commits to scan."
exit 0
fi
COUNT=$(echo "$COMMITS" | wc -l | tr -d ' ')
echo "Commit count: $COUNT"
# AI co-author trailer pattern(全大小写;覆盖 anthropic / claude / cursor /
# copilot 子串)
TRAILER_RE='Co-[Aa]uthored-[Bb]y:.*<[^>]*(@anthropic\.com|cursor|[Cc]opilot|cursoragent|claude)'
# AI author email pattern
EMAIL_RE='@anthropic\.com|cursoragent@cursor|copilot-swe-agent|[Cc]ursor@users\.noreply|[Cc]opilot@users\.noreply'
FAILED=0
for sha in $COMMITS; do
short=$(git log -1 --format='%h' "$sha")
msg=$(git log -1 --format='%B' "$sha")
ae=$(git log -1 --format='%ae' "$sha")
ce=$(git log -1 --format='%ce' "$sha")
if echo "$msg" | grep -iE "$TRAILER_RE" > /dev/null; then
echo "::error::commit $short: AI Co-Authored-By trailer detected"
echo "$msg" | grep -iE "$TRAILER_RE" || true
FAILED=1
fi
if echo "$ae" | grep -iE "$EMAIL_RE" > /dev/null; then
echo "::error::commit $short: AI author email — $ae"
FAILED=1
fi
if echo "$ce" | grep -iE "$EMAIL_RE" > /dev/null; then
echo "::error::commit $short: AI committer email — $ce"
FAILED=1
fi
done
if [ "$FAILED" -ne 0 ]; then
echo "::error::Found AI co-author trailer or AI email in $RANGE."
echo "::error::Rewrite commit message (git commit --amend / rebase -i) to remove,"
echo "::error::or force-push with corrected history."
exit 1
fi
echo "✅ No AI co-author trailers or emails in $COUNT commits."