Skip to content

chore(deps): lock file maintenance #2226

chore(deps): lock file maintenance

chore(deps): lock file maintenance #2226

name: Check Attribution
on:
# Every pull request, not only those targeting main: a stacked pull request
# is based on the branch below it, and a trailer that slips through there
# reaches main when the stack merges.
pull_request:
# Coding agents sign their work either with a Co-Authored-By trailer or by
# claiming the author/committer field. Squash-merging collects the trailers of
# every commit in the PR into the merge commit, so a single unnoticed trailer
# reaches main permanently. Each identity below is a vendor-controlled address
# or a known agent's GitHub App handle. Dependency bots (dependabot, renovate)
# are deliberately allowed: they are maintenance automation, not authorship
# claims.
env:
# Bare identities, matched against a trailer address and against the
# author/committer fields. The optional digits cover GitHub's
# "<id>+<handle>@users.noreply.github.com" form, whose id varies per app.
AI_IDENTITY_RE: '(noreply@anthropic\.com|cursoragent@cursor\.com|(noreply|codex)@openai\.com|noreply@aider\.chat|openhands@all-hands\.dev|noreply@opencode\.ai|noreply@continue\.dev|clio-agent@sisyphuslabs\.ai|roomote@roocode\.com|copilot@github\.com|([0-9]+[+])?(Copilot|gemini-code-assist\[bot\]|greptile-apps\[bot\]|coderabbitai\[bot\]|ellipsis-dev\[bot\]|qodo-merge-pro\[bot\]|sweep-ai\[bot\]|bito-code-review\[bot\]|roomote\[bot\]|factory-droid\[bot\]|opencode-agent\[bot\]|google-labs-jules\[bot\])@users\.noreply\.github\.com)'
jobs:
check-bot-coauthors:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
fetch-depth: 0
- name: Check for bot Co-Authored-By lines
env:
BASE_REF: ${{ github.base_ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
COMMITS=$(git log --format='%H' "origin/${BASE_REF}..${HEAD_SHA}" 2>/dev/null || true)
if [ -z "$COMMITS" ]; then
echo "No commits to check"
exit 0
fi
# Anchored to a full trailer line so a mention in prose does not fail.
TRAILER_RE="^[[:space:]]*co-authored-by:[[:space:]]+.*<${AI_IDENTITY_RE}>[[:space:]]*$"
FOUND=0
for sha in $COMMITS; do
MSG=$(git log --format='%B' -1 "$sha")
HITS=$(printf '%s\n' "$MSG" | grep -Ei "$TRAILER_RE" || true)
if [ -n "$HITS" ]; then
echo "::error::Commit $sha contains a bot Co-Authored-By line. Remove it with: git rebase -i and edit the commit message."
printf '%s\n' "$HITS"
FOUND=1
fi
done
if [ "$FOUND" -eq 1 ]; then
echo ""
echo "To fix: run 'git rebase -i origin/main', change 'pick' to 'reword' for flagged commits, then remove the Co-Authored-By lines."
exit 1
fi
echo "All commits clean."
- name: Check for bot commit authors
env:
BASE_REF: ${{ github.base_ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Some agents (Copilot's cloud agent, Jules, Devin) claim the author
# or committer field instead of adding a trailer, so the check above
# cannot see them. Written to a file rather than piped so the loop
# runs in this shell and its result survives.
git log --format='%H %ae %ce' "origin/${BASE_REF}..${HEAD_SHA}" > /tmp/authors.txt 2>/dev/null || true
FOUND=0
while read -r sha author committer; do
[ -z "$sha" ] && continue
for addr in "$author" "$committer"; do
if printf '%s\n' "$addr" | grep -Eqi "^${AI_IDENTITY_RE}$"; then
echo "::error::Commit $sha is authored or committed by a coding agent: $addr"
FOUND=1
fi
done
done < /tmp/authors.txt
if [ "$FOUND" -eq 1 ]; then
echo ""
echo "To fix: rewrite the commit with 'git rebase -i origin/main', then 'git commit --amend --author=\"Your Name <you@example.com>\"'."
exit 1
fi
echo "All commit authors clean."