Skip to content

Commit 5fa9790

Browse files
committed
ci: add agent-scan workflow to flag bot-authored PRs
1 parent f84e575 commit 5fa9790

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

.github/workflows/agent-scan.yml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
name: agent-scan
2+
3+
on:
4+
# zizmor: ignore[dangerous-triggers] - DO NOT add action/checkout in this workflow as it uses pull_request_target
5+
pull_request_target:
6+
types:
7+
- opened
8+
- reopened
9+
10+
concurrency:
11+
group: agent-scan-${{ github.event.pull_request.number }}
12+
cancel-in-progress: true
13+
14+
permissions:
15+
issues: write
16+
pull-requests: write
17+
18+
jobs:
19+
agentscan:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: AgentScan
23+
id: agentscan
24+
uses: MatteoGabriele/agentscan-action@ccb50da057e2ac7fcdb123db3110f00af97f0fef # v1.14.0
25+
with:
26+
github-token: ${{ secrets.GITHUB_TOKEN }}
27+
skip-members: "dependabot[bot],renovate[bot]"
28+
agent-scan-comment: false
29+
- name: Handle flagged PR
30+
if: contains(fromJSON('["automation","mixed"]'), steps.agentscan.outputs.classification) || steps.agentscan.outputs.community-flagged == 'true'
31+
env:
32+
CLASSIFICATION: ${{ steps.agentscan.outputs.classification }}
33+
COMMUNITY_FLAGGED: ${{ steps.agentscan.outputs.community-flagged }}
34+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
35+
with:
36+
script: |
37+
const prNumber = context.payload.pull_request.number;
38+
const classification = process.env.CLASSIFICATION;
39+
const communityFlagged = process.env.COMMUNITY_FLAGGED === 'true';
40+
const shouldClose = classification === 'automation' || communityFlagged;
41+
42+
const issue = context.payload.pull_request
43+
const labels = issue.labels?.map(l => l.name) || []
44+
45+
if (!labels.includes('possible bot')) {
46+
await github.rest.issues.addLabels({
47+
owner: context.repo.owner,
48+
repo: context.repo.repo,
49+
issue_number: prNumber,
50+
labels: ['possible bot'],
51+
})
52+
}
53+
54+
const comments = await github.paginate(github.rest.issues.listComments, {
55+
owner: context.repo.owner,
56+
repo: context.repo.repo,
57+
issue_number: prNumber,
58+
per_page: 100,
59+
})
60+
61+
const alreadyCommented = comments.some(
62+
c => c.user.type === 'Bot' && c.body.includes('AI-assisted contribution guidelines')
63+
)
64+
65+
if (!alreadyCommented) {
66+
const closingNote = shouldClose
67+
? "We're closing this for now as the account looks automated. If we got that wrong, please just reopen the PR and we'll take another look."
68+
: 'If this was flagged in error, we apologise! 😳 Just let us know. 🙏'
69+
70+
await github.rest.issues.createComment({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
issue_number: prNumber,
74+
body: [
75+
"We've flagged this as a potential contribution without a human behind it. We welcome the thoughtful use of AI tools when contributing, but ask all contributors to follow [two core principles](https://roe.dev/blog/using-ai-in-open-source):",
76+
'',
77+
'1. **Never let an LLM speak for you** - all comments, issues, and PR descriptions should be written in your own words, reflecting your own understanding.',
78+
'2. **Never let an LLM think for you** - only submit contributions you fully understand and can explain.',
79+
'',
80+
'Please review these AI-assisted contribution guidelines and update this contribution if needed.',
81+
'',
82+
closingNote,
83+
].join('\n'),
84+
})
85+
} else {
86+
core.info('Possible-bot comment already exists - skipping comment.')
87+
}
88+
89+
if (shouldClose && issue.state === 'open' && !alreadyCommented) {
90+
await github.rest.pulls.update({
91+
owner: context.repo.owner,
92+
repo: context.repo.repo,
93+
pull_number: prNumber,
94+
state: 'closed',
95+
title: '🚨 unwelcome pr from bot 🚨',
96+
})
97+
}
98+
99+
const actionTaken = [
100+
'Added `possible bot` label',
101+
alreadyCommented ? null : 'posted policy comment',
102+
shouldClose && !alreadyCommented ? 'closed PR' : null,
103+
].filter(Boolean).join(', ')
104+
105+
core.summary
106+
.addHeading('AgentScan: Possible Bot Flag', 2)
107+
.addTable([
108+
[{ data: 'Property', header: true }, { data: 'Value', header: true }],
109+
['Pull Request', `#${prNumber}`],
110+
['Classification', classification],
111+
['Community flagged', String(communityFlagged)],
112+
['Action', actionTaken || 'No action (already handled)'],
113+
])
114+
115+
await core.summary.write()

0 commit comments

Comments
 (0)