Skip to content

Commit c71838f

Browse files
authored
[universal]: Add non verified commit warning github action (CloudPirates-io#335)
* Add non verified commit warning github action * Recognize ssh signing * Fix unset git option * Test change to verify without signature message * Test change to verify without signature message * Test change to verify without signature message
1 parent f7ff0cf commit c71838f

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: "Check Signed Commits"
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- synchronize
8+
- reopened
9+
branches:
10+
- main
11+
12+
jobs:
13+
check-signed-commits:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
pull-requests: write
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v5.0.0
21+
with:
22+
fetch-depth: 0
23+
ref: ${{ github.event.pull_request.head.sha }}
24+
25+
- name: Configure Git for SSH signature verification
26+
run: |
27+
# Create a temporary allowed signers file (not used for actual verification)
28+
# This allows git to recognize SSH signatures exist without requiring key validation
29+
touch /tmp/allowed_signers
30+
git config --global gpg.ssh.allowedSignersFile /tmp/allowed_signers
31+
# Configure git to recognize SSH signing format
32+
git config --global gpg.format ssh
33+
34+
- name: Check for verified commits
35+
id: check-commits
36+
run: |
37+
# Get all commits in the PR
38+
git fetch origin ${{ github.event.pull_request.base.ref }}
39+
COMMITS=$(git rev-list origin/${{ github.event.pull_request.base.ref }}..${{ github.event.pull_request.head.sha }})
40+
41+
UNSIGNED_COMMITS=""
42+
UNSIGNED_COUNT=0
43+
TOTAL_COUNT=0
44+
45+
for commit in $COMMITS; do
46+
TOTAL_COUNT=$((TOTAL_COUNT + 1))
47+
# Check if commit is signed (GPG or SSH signature)
48+
# %G? returns signature status
49+
# %GF returns the signing key fingerprint (empty if not signed)
50+
SIGNATURE=$(git log -1 --format='%G?' $commit)
51+
FINGERPRINT=$(git log -1 --format='%GF' $commit)
52+
53+
# %G? returns:
54+
# G = good GPG signature
55+
# U = unverified signature (has signature but can't verify - common for SSH)
56+
# B = bad signature
57+
# N = no signature
58+
# E = signature expired
59+
# Y = good signature (expired key)
60+
61+
# A commit is considered SIGNED if it has any signature present
62+
# We check for a fingerprint to confirm a signature exists
63+
# For SSH signatures, %G? will be "U" but %GF will have the fingerprint
64+
65+
if [[ -z "$FINGERPRINT" ]]; then
66+
# No fingerprint means no signature at all
67+
UNSIGNED_COMMITS="${UNSIGNED_COMMITS}${commit}\n"
68+
UNSIGNED_COUNT=$((UNSIGNED_COUNT + 1))
69+
fi
70+
done
71+
72+
echo "total_commits=${TOTAL_COUNT}" >> $GITHUB_OUTPUT
73+
echo "unsigned_commits=${UNSIGNED_COUNT}" >> $GITHUB_OUTPUT
74+
75+
if [ $UNSIGNED_COUNT -gt 0 ]; then
76+
echo "has_unsigned=true" >> $GITHUB_OUTPUT
77+
else
78+
echo "has_unsigned=false" >> $GITHUB_OUTPUT
79+
fi
80+
81+
- name: Check if comment already exists
82+
if: steps.check-commits.outputs.has_unsigned == 'true'
83+
id: check-comment
84+
env:
85+
GH_TOKEN: ${{ github.token }}
86+
run: |
87+
# Check if our bot has already commented on this PR
88+
COMMENT_EXISTS=$(gh api \
89+
-H "Accept: application/vnd.github+json" \
90+
-H "X-GitHub-Api-Version: 2022-11-28" \
91+
"/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments" \
92+
| jq -r '.[] | select(.user.login == "github-actions[bot]" and (.body | contains("⚠️ Unsigned Commits Detected"))) | .id' | head -1)
93+
94+
if [ -n "$COMMENT_EXISTS" ]; then
95+
echo "comment_exists=true" >> $GITHUB_OUTPUT
96+
echo "comment_id=${COMMENT_EXISTS}" >> $GITHUB_OUTPUT
97+
else
98+
echo "comment_exists=false" >> $GITHUB_OUTPUT
99+
fi
100+
101+
- name: Post warning comment
102+
if: steps.check-commits.outputs.has_unsigned == 'true' && steps.check-comment.outputs.comment_exists == 'false'
103+
env:
104+
GH_TOKEN: ${{ github.token }}
105+
run: |
106+
cat << 'EOF' | gh pr comment ${{ github.event.pull_request.number }} --repo ${{ github.repository }} -F -
107+
## ⚠️ Unsigned Commits Detected
108+
109+
This pull request contains unsigned commits.
110+
111+
### What does this mean?
112+
113+
Signed commits help ensure the authenticity and traceability of contributions. They allow us to verify that commits actually came from the stated author, even if GitHub accounts are deleted or modified in the future.
114+
115+
### Current Policy (Grace Period)
116+
117+
**This is currently a warning only.** We are in a transition period to give all contributors time to set up commit signing.
118+
119+
After this grace period, **all commits will be required to be signed** before PRs can be merged.
120+
121+
### How to sign your commits
122+
123+
Please see our [Contributing Guide](../blob/main/CONTRIBUTING.md#setting-up-your-development-environment) for detailed instructions on setting up commit signing.
124+
125+
### Resources
126+
127+
- [Contributing Guide: Development Setup](../blob/main/CONTRIBUTING.md#setting-up-your-development-environment)
128+
- [GitHub Docs: About Commit Signature Verification](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
129+
130+
---
131+
132+
_This check will become mandatory in the future. Please start signing your commits now to avoid issues later._
133+
EOF
134+
135+
- name: Success message
136+
if: steps.check-commits.outputs.has_unsigned == 'false'
137+
run: |
138+
echo "✅ All ${{ steps.check-commits.outputs.total_commits }} commits in this PR are signed!"
139+

0 commit comments

Comments
 (0)