From d61b5e65f940f722e5610c36201b42bf0f3d70f1 Mon Sep 17 00:00:00 2001 From: DeathGun44 Date: Sun, 1 Feb 2026 02:48:17 +0530 Subject: [PATCH] FINERACT-2177: Add Git signed commits verification --- .github/workflows/verify-commits.yml | 47 ++++++++++++++ CONTRIBUTING.md | 12 ++++ scripts/verify-signed-commits.sh | 97 ++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+) create mode 100644 .github/workflows/verify-commits.yml create mode 100755 scripts/verify-signed-commits.sh diff --git a/.github/workflows/verify-commits.yml b/.github/workflows/verify-commits.yml new file mode 100644 index 000000000..a8c13feec --- /dev/null +++ b/.github/workflows/verify-commits.yml @@ -0,0 +1,47 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +name: Fineract Signed Commits Check + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + +jobs: + verify-signatures: + name: Verify Commit Signatures + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Fetch base branch + run: git fetch origin ${{ github.base_ref }} + + - name: Verify signatures + run: | + chmod +x scripts/verify-signed-commits.sh + ./scripts/verify-signed-commits.sh \ + --base-ref origin/${{ github.base_ref }} \ + --head-ref ${{ github.sha }} \ + --strict diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c243b4c51..d7883c32b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -270,3 +270,15 @@ This project's committers typically prefer to bring your pull requests in throug We expect most proposed PRs to typically consist of a single commit. Committers may use _Squash and merge_ to combine your commits at merge time, and if they do so, will rewrite your commit message as they see fit. Neither of these two are hard absolute rules, but mere conventions. Multiple commits in single PRs make sense in certain cases (e.g. branch backports). + +### Signing Your Commits + +We encourage contributors to sign commits with GPG keys. Signed commits show a "Verified" badge on GitHub. + +For GPG setup instructions, see the [Fineract GPG Guide](https://fineract.apache.org/docs/current/#_gpg_2). + +To verify your commits locally before pushing: + +```bash +./scripts/verify-signed-commits.sh +``` diff --git a/scripts/verify-signed-commits.sh b/scripts/verify-signed-commits.sh new file mode 100755 index 000000000..918eaabf9 --- /dev/null +++ b/scripts/verify-signed-commits.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Usage: ./scripts/verify-signed-commits.sh [--base-ref ] [--head-ref ] [--strict] [--help] +set -e + +BASE_REF="origin/develop" +HEAD_REF="HEAD" +STRICT_MODE=false + +show_help() { + cat << 'EOF' +Usage: ./scripts/verify-signed-commits.sh [OPTIONS] + +Options: + --base-ref Base reference (default: origin/develop) + --head-ref Head reference (default: HEAD) + --strict Exit with error if unsigned commits found + --help Show this help +EOF +} + +while [[ $# -gt 0 ]]; do + case $1 in + --base-ref) BASE_REF="$2"; shift 2 ;; + --head-ref) HEAD_REF="$2"; shift 2 ;; + --strict) STRICT_MODE=true; shift ;; + --help) show_help; exit 0 ;; + *) echo "Unknown option: $1"; show_help; exit 1 ;; + esac +done + +MERGE_BASE=$(git merge-base "$BASE_REF" "$HEAD_REF" 2>/dev/null || echo "") +if [ -z "$MERGE_BASE" ]; then + COMMIT_RANGE="$HEAD_REF~10..$HEAD_REF" +else + COMMIT_RANGE="$MERGE_BASE..$HEAD_REF" +fi + +echo "Verifying commit signatures in range: $COMMIT_RANGE" + +COMMITS=$(git log --format="%H%x1f%G?%x1f%an%x1f%s" "$COMMIT_RANGE" 2>/dev/null || echo "") +if [ -z "$COMMITS" ]; then + echo "No commits to verify." + exit 0 +fi + +UNSIGNED_COUNT=0 + +while IFS=$'\x1f' read -r HASH SIG_STATUS AUTHOR SUBJECT; do + [ -z "$HASH" ] && continue + SHORT_HASH="${HASH:0:7}" + + case "$SIG_STATUS" in + N) + UNSIGNED_COUNT=$((UNSIGNED_COUNT + 1)) + if [ -n "$GITHUB_ACTIONS" ]; then + echo "::error title=Unsigned Commit::Commit $SHORT_HASH by $AUTHOR is not signed." + else + echo "❌ Unsigned: $SHORT_HASH - $SUBJECT ($AUTHOR)" + fi + ;; + *) + echo "✅ Signed: $SHORT_HASH - $SUBJECT" + ;; + esac +done <<< "$COMMITS" + +echo "" +echo "Summary: $UNSIGNED_COUNT unsigned commit(s) found." + +if [ "$STRICT_MODE" = true ] && [ "$UNSIGNED_COUNT" -gt 0 ]; then + if [ -n "$GITHUB_ACTIONS" ]; then + echo "::error::$UNSIGNED_COUNT unsigned commit(s). See CONTRIBUTING.md#signing-your-commits" + else + echo "❌ $UNSIGNED_COUNT unsigned commit(s). See CONTRIBUTING.md#signing-your-commits" + fi + exit 1 +fi + +exit 0