Repository navigation
ci: reject commits that carry AI attribution - #8
Merged
Merged
Conversation
A script checks the commits of each pull request or push for AI co-author or assistant trailers, "Generated with" footers and AI author or committer identities, and the verify job runs it as pnpm check:attribution. Human co-authors are allowed, and so is prose that only mentions Claude. The rules are tested against throw-away repositories (tests/check-attribution.test.ts, run by pnpm test and pnpm check). The step catches what the local commit-msg guard cannot: a commit made with --no-verify, with hooks disabled, or built with git commit-tree.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The public history was rewritten on 2026-10-24 to remove AI co-author trailers. A local Git hook strips them from new commits and refuses pushes that carry them, but a local hook can be bypassed (
--no-verify, hooks disabled, a cherry-pick,git commit-tree) and does not exist for other contributors. This adds a server-side check to the requiredverifyjob so such a commit cannot reachmainunnoticed.What changes
scripts/check-attribution.mjs: reads the commits of the current pull request (base..headfrom the GitHub event) or push (before..after), falling back to the last 20 commits when there is no event. It fails (exit 1, with a GitHub::errorannotation) onCo-authored-by,Co-developed-by,Assisted-by,Generated-by,Signed-off-by) that names Claude, Anthropic, Copilot, ChatGPT, OpenAI, Codex or Gemini,Human co-authors pass, and so does prose that only mentions Claude: the subject line (first line) is never judged, and a body line is judged only if it is a trailer or a footer.
Also
--range A..B,--all(audit of every ref) and--self-test.tests/check-attribution.test.ts: runs the self-test (20 cases against throw-away repositories) insidepnpm test, sopnpm checkalso covers the rules.package.json:check:attributionscript..github/workflows/ci.yml: one- run: pnpm check:attributionstep inverify, afterscan:secrets. The existing pinned action SHAs are untouched. Becauseverifyis the required check on theProtect mainruleset, the check is enforced for every pull request.CONTRIBUTING.md: one bullet.No application source changes.
Verified
Locally, on this branch rebased onto the merged dependency fix (main cfe6dac):
pnpm install --frozen-lockfile,tsc -b --noEmit, worker typecheck,pnpm test(46 files, 656 tests),pnpm scan:secrets,pnpm check:attribution,pnpm audit(no known vulnerabilities) andpnpm buildall pass.--allover every ref of the public repository reports clean.Detection, tried in a scratch clone with commits that skip the local commit-msg hook (exit status of the checker; 1 = rejected):
git commit --no-verify-c core.hooksPath=/dev/null(all hooks off)git commit-tree--no-verify--no-verifypull_requestevent payloadCo-authored-by: Sam RiveraThe same bad commit was also refused by the global pre-push hook on the owner's machine (the second line of defence); that hook's own test suite passes and it chains to a repository's own hooks.
Known limits
main.