Skip to content

Commit ff4fdda

Browse files
committed
update CLA workflow: API-based bot detection, check all committers, reduce permissions
1 parent a900d55 commit ff4fdda

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

.github/workflows/cla.yml

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ on:
66
types: [opened, closed, synchronize]
77

88
permissions:
9-
actions: write
10-
contents: write
119
pull-requests: write
1210
statuses: write
1311

@@ -23,36 +21,67 @@ jobs:
2321
private-key: ${{ secrets.APP_PRIVATE_KEY }}
2422
owner: blacklanternsecurity
2523

26-
- name: Check org membership
27-
id: membership
24+
- name: Check all committers against org and allowlist
25+
id: cla-check
2826
env:
2927
GH_TOKEN: ${{ steps.app-token.outputs.token }}
3028
run: |
3129
if [ "${{ github.event_name }}" = "pull_request_target" ]; then
32-
AUTHOR="${{ github.event.pull_request.user.login }}"
30+
PR_NUM="${{ github.event.pull_request.number }}"
3331
else
3432
PR_NUM="${{ github.event.issue.number }}"
35-
AUTHOR=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUM" --jq '.user.login' 2>/dev/null)
36-
fi
37-
if [ -n "$AUTHOR" ] && gh api "orgs/blacklanternsecurity/members/$AUTHOR" > /dev/null 2>&1; then
38-
echo "is_member=true" >> "$GITHUB_OUTPUT"
39-
else
40-
echo "is_member=false" >> "$GITHUB_OUTPUT"
4133
fi
4234
43-
- name: Skip CLA for org members
44-
if: steps.membership.outputs.is_member == 'true' && github.event_name == 'pull_request_target'
35+
COMMITTERS=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUM/commits" --paginate --jq '.[].author.login' | sort -u)
36+
ALL_EXEMPT=true
37+
38+
for LOGIN in $COMMITTERS; do
39+
# treat commits with no associated GitHub login as non-exempt
40+
if [ -z "$LOGIN" ] || [ "$LOGIN" = "null" ]; then
41+
echo "Unknown committer (no GitHub login) — not exempt"
42+
ALL_EXEMPT=false
43+
break
44+
fi
45+
46+
EXEMPT=false
47+
48+
# check if account type is Bot (GitHub App accounts)
49+
AUTHOR_TYPE=$(gh api "users/${LOGIN}" --jq '.type' 2>/dev/null || echo "Unknown")
50+
if [ "$AUTHOR_TYPE" = "Bot" ]; then
51+
echo "$LOGIN is a Bot account — exempt"
52+
EXEMPT=true
53+
fi
54+
55+
# check org membership
56+
if [ "$EXEMPT" = "false" ]; then
57+
if gh api "orgs/blacklanternsecurity/members/$LOGIN" > /dev/null 2>&1; then
58+
echo "$LOGIN is an org member — exempt"
59+
EXEMPT=true
60+
fi
61+
fi
62+
63+
if [ "$EXEMPT" = "false" ]; then
64+
echo "$LOGIN is not exempt — CLA required"
65+
ALL_EXEMPT=false
66+
break
67+
fi
68+
done
69+
70+
echo "all_exempt=$ALL_EXEMPT" >> "$GITHUB_OUTPUT"
71+
72+
- name: Skip CLA when all committers are exempt
73+
if: steps.cla-check.outputs.all_exempt == 'true' && github.event_name == 'pull_request_target'
4574
env:
4675
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4776
run: |
4877
gh api --method POST "repos/${{ github.repository }}/statuses/${{ github.event.pull_request.head.sha }}" \
4978
-f state=success \
5079
-f context="CLAAssistant" \
51-
-f description="CLA check skipped — author is an org member"
80+
-f description="CLA check skipped — all committers are org members or bots"
5281
5382
- name: "CLA Assistant"
5483
if: |
55-
(steps.membership.outputs.is_member != 'true') &&
84+
(steps.cla-check.outputs.all_exempt != 'true') &&
5685
((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target')
5786
uses: contributor-assistant/github-action@v2.6.1
5887
env:

0 commit comments

Comments
 (0)