|
| 1 | +name: Verify Signatures |
| 2 | + |
| 3 | +on: |
| 4 | + pull_request: |
| 5 | + branches: [master] |
| 6 | + push: |
| 7 | + branches: [master] |
| 8 | + |
| 9 | +permissions: |
| 10 | + contents: read |
| 11 | + |
| 12 | +jobs: |
| 13 | + verify: |
| 14 | + name: Verify GPG Signatures |
| 15 | + runs-on: ubuntu-latest |
| 16 | + steps: |
| 17 | + - name: Checkout code |
| 18 | + uses: actions/checkout@v6 |
| 19 | + with: |
| 20 | + fetch-depth: 0 |
| 21 | + |
| 22 | + - name: Verify all commits are signed (via GitHub API) |
| 23 | + env: |
| 24 | + GH_TOKEN: ${{ github.token }} |
| 25 | + run: | |
| 26 | + echo "Checking commits in this PR/push via GitHub API..." |
| 27 | +
|
| 28 | + if [ "${{ github.event_name }}" == "pull_request" ]; then |
| 29 | + BASE_SHA="${{ github.event.pull_request.base.sha }}" |
| 30 | + HEAD_SHA="${{ github.event.pull_request.head.sha }}" |
| 31 | + else |
| 32 | + # For push events, check commits |
| 33 | + HEAD_SHA="${{ github.sha }}" |
| 34 | + BEFORE_SHA="${{ github.event.before }}" |
| 35 | +
|
| 36 | + # Handle new branches where github.event.before is null SHA |
| 37 | + if [ "${BEFORE_SHA}" = "0000000000000000000000000000000000000000" ]; then |
| 38 | + echo "New branch detected, checking all commits since master..." |
| 39 | + BASE_SHA=$(git merge-base origin/master ${HEAD_SHA} 2>/dev/null || echo "") |
| 40 | + if [ -z "$BASE_SHA" ]; then |
| 41 | + echo "No common ancestor with master, checking only HEAD commit" |
| 42 | + BASE_SHA="${HEAD_SHA}^" |
| 43 | + fi |
| 44 | + else |
| 45 | + BASE_SHA="${BEFORE_SHA}" |
| 46 | + fi |
| 47 | + fi |
| 48 | +
|
| 49 | + COMMITS=$(git rev-list ${BASE_SHA}..${HEAD_SHA} 2>/dev/null || echo "${HEAD_SHA}") |
| 50 | + UNSIGNED_COMMITS=() |
| 51 | +
|
| 52 | + for commit in $COMMITS; do |
| 53 | + # Use GitHub API to check signature verification |
| 54 | + VERIFIED=$(gh api repos/${{ github.repository }}/commits/${commit} --jq '.commit.verification.verified') |
| 55 | + if [ "$VERIFIED" != "true" ]; then |
| 56 | + UNSIGNED_COMMITS+=("$commit") |
| 57 | + REASON=$(gh api repos/${{ github.repository }}/commits/${commit} --jq '.commit.verification.reason') |
| 58 | + echo "❌ Commit $commit is NOT verified (reason: $REASON)" |
| 59 | + else |
| 60 | + echo "✅ Commit $commit is verified" |
| 61 | + fi |
| 62 | + done |
| 63 | +
|
| 64 | + if [ ${#UNSIGNED_COMMITS[@]} -gt 0 ]; then |
| 65 | + echo "" |
| 66 | + echo "ERROR: Found ${#UNSIGNED_COMMITS[@]} unverified commit(s)!" |
| 67 | + echo "" |
| 68 | + echo "All commits must be GPG-signed for security packages." |
| 69 | + echo "See CONTRIBUTING.md for setup instructions." |
| 70 | + exit 1 |
| 71 | + fi |
| 72 | +
|
| 73 | + echo "" |
| 74 | + echo "✅ All commits are verified!" |
| 75 | +
|
| 76 | + - name: Verify tag signature (if tagged) |
| 77 | + if: startsWith(github.ref, 'refs/tags/') |
| 78 | + env: |
| 79 | + GH_TOKEN: ${{ github.token }} |
| 80 | + run: | |
| 81 | + TAG="${{ github.ref_name }}" |
| 82 | + # Use GitHub API to check tag verification |
| 83 | + VERIFIED=$(gh api repos/${{ github.repository }}/git/tags/$(gh api repos/${{ github.repository }}/git/ref/tags/${TAG} --jq '.object.sha') --jq '.verification.verified' 2>/dev/null || echo "false") |
| 84 | + if [ "$VERIFIED" != "true" ]; then |
| 85 | + echo "❌ Tag $TAG is NOT verified" |
| 86 | + echo "Create signed tags with: git tag -s" |
| 87 | + exit 1 |
| 88 | + fi |
| 89 | + echo "✅ Tag $TAG is verified" |
0 commit comments