diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index ea39c5a9..acb56a11 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -42,7 +42,11 @@ jobs: run: npm ci - name: Validate PR commits with commitlint - run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose + run: ./scripts/filter-commits-by-author.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} "${{ vars.COMMITLINT_EXCLUDED_AUTHORS || '' }}" + env: + # Optional: Set COMMITLINT_EXCLUDED_AUTHORS as a repository variable to exclude specific authors + # Example value: "bot@example.com,dependabot[bot],renovate[bot]" + EXCLUDED_AUTHORS: ${{ vars.COMMITLINT_EXCLUDED_AUTHORS || '' }} build: name: Build diff --git a/README.md b/README.md index 4cf65b35..9a4e23f3 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,35 @@ npm run container:build:master-bitgo-express npm run container:build:advanced-wallet-manager ``` +### CI/CD - Commit Filtering + +The repository includes a commit filtering script for CI/CD workflows that allows excluding commits from specific authors during commitlint validation. This is useful for skipping validation of automated commits from bots or tools. + +#### Usage in GitHub Actions + +The workflow automatically uses the `filter-commits-by-author.sh` script. To configure author exclusions, set the `COMMITLINT_EXCLUDED_AUTHORS` repository variable in GitHub: + +1. Go to your repository Settings → Secrets and variables → Actions → Variables +2. Create a new variable named `COMMITLINT_EXCLUDED_AUTHORS` +3. Set the value to a comma-separated list of authors to exclude, for example: + ``` + dependabot[bot],renovate[bot],copilot-swe-agent[bot] + ``` + +#### Manual Usage + +You can also run the script manually: + +```bash +# Validate all commits between two refs +./scripts/filter-commits-by-author.sh + +# Exclude specific authors +./scripts/filter-commits-by-author.sh "bot@example.com,dependabot[bot]" +``` + +The script matches author emails and names using substring matching, so you can specify partial matches like "bot" to exclude all bot accounts. + ## Quick Start ### Quick Start (No mTLS) - Fastest Way to Test diff --git a/demo.crt b/demo.crt index 3ebdef5d..dc77e827 100644 --- a/demo.crt +++ b/demo.crt @@ -1,24 +1,19 @@ -----BEGIN CERTIFICATE----- -MIID9TCCAt2gAwIBAgIUKCkJ6fcl2+2EsK0n9v7iqGu1qgIwDQYJKoZIhvcNAQEL -BQAwgYkxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250 -bzEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDDAZQ -cmFuYXYxJzAlBgkqhkiG9w0BCQEWGHByYW5hdmphaW4xMTk3QGdtYWlsLmNvbTAe -Fw0yNTA4MDEyMjE4MTVaFw0yNjA4MDEyMjE4MTVaMIGJMQswCQYDVQQGEwJDQTEL -MAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8xITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGUHJhbmF2MScwJQYJKoZIhvcNAQkB -FhhwcmFuYXZqYWluMTE5N0BnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQC+QfWH5GbQidrIawVbjZ7RL/uZtF7wbmacER2wYlOO7Ib+Je1h -03P3BQlI5bTBE3KkxrwDqycxWk/MA9hj2VT1tL3+bE/yuYVaOgGN4fiibG9Cc8MG -MrWsZKRvP5Hy/ZUobVfLAPXvpUKM+nf//MaO6x9F/9TEwIb9rqfoD+bynL1s2LhR -wr2ppYZXoOmdS/yhEiXloX4fO//5ivC/1zpt6bYaqdA2WAkBHyM24LOm02lJvRV+ -oq5dFxH0c0YCAEe05QfVLXgb/S/JTpxfOlabAVomb9+9ESOpEWqCyOo3U3QaSh49 -FdCUGFnaZHXc4324E/La955dSdeziLlDKXrdAgMBAAGjUzBRMB0GA1UdDgQWBBSe -jCcPNqJHmbsXhsdKaJj9BUIhfTAfBgNVHSMEGDAWgBSejCcPNqJHmbsXhsdKaJj9 -BUIhfTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQARJW7QnfwS -afy2M9ShDC7mqVa54LOaT6Ics+QYRPvJIRazlkODGm/n49rYZatgUNN1ouK6m7xk -HuycnsWFZKly+w0/ugoe9fK59KUJCFNtPlTrAmJM4/x2yzSky/XlqEt0n8L8U8N1 -dbWcIC8EWNcUVKCKiS8ecoOm4G34I7YFOc5JwqEPJwfaQ76EHTKwEQe3MtM+wZaQ -TrSm8WuYwlio53nyoyHHNGnJLKuN9DjOp9VdAtJcgCU8TutlKxAn1aDixrjcuzrk -cqxn97OnE6eXsHurFY193lFs0HWpIAztXhjdtLjFJy68nVVmPcWAAWbcu4JhbBUX -jZJ7DNuCDOoV +MIIDCTCCAfGgAwIBAgIUSGNuz9bTAHWDWMoJ/7LZlhZyawwwDQYJKoZIhvcNAQEL +BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTExMjIwNDkwOVoXDTI2MTEx +MjIwNDkwOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAm3s7+m/jQj2J5ud1d6rBYbypG/9EenhrqS0zunjuGRCh +OEXHiOZUKqpZPp+FVsbbuQIoRlFkkx5QtbSqMbAMxlQAnWpqIASDLwpYqBRMrtTX +HB/aYuwGig1qk0+wlduXV+c5rmuDROs/g4ljFJqrVee/OBIaXst+Bng2CpA4zPgo +sKN0+MN/UQtgpM78Eo3IAerAFgvJXpPezDZ3zMg6oVVZvDNU7RzmLO7OifzoZevC +zkdCuNT9vEh4ulUOmgJLeI+ez2v92dL0yyrzlToih8KO7OUJF3TE7QfJMkapGmtU +JAAihWqzj8q6HAQ6gvugm2mUlAvAwFPGlL8vNp8WCQIDAQABo1MwUTAdBgNVHQ4E +FgQUd3RBEgBv1xX1tFw0hcLxFE1jWJ8wHwYDVR0jBBgwFoAUd3RBEgBv1xX1tFw0 +hcLxFE1jWJ8wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAOb8d +7SPhJo0Gx6yoiC0yZE4Yi7o6MqWlq9SabVjtc613K8AVHkDWdhN3+SKHKdpONCR+ +BxRuIcSLVyhhhKC6t5Nwl3PRn7HP/POnAfIpE7badMqR8KzBgOu9SDXIPwXdsRiX +KoMGiG78Q7SFOD/Tl3cjO7ifAGie9FHumJWpVGI5hQ4hhTzAkxAyQ5w3cghAIZ1q +R/24bgQI5hDMu4+iQqi50fFY7ycolAeeC7JxVKbbtCYdbDcHWm+7yQxEFQutaRBx +1v85GQ7Lcq3iiPTgncoTmxCiwXv37/TGINQ8izAo1lXjjRI8VqNEGolvHlUYChXn +CsOqGDrfJIXe2XEmcg== -----END CERTIFICATE----- diff --git a/demo.key b/demo.key index 8473ea77..5bf5bbbf 100644 --- a/demo.key +++ b/demo.key @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+QfWH5GbQidrI -awVbjZ7RL/uZtF7wbmacER2wYlOO7Ib+Je1h03P3BQlI5bTBE3KkxrwDqycxWk/M -A9hj2VT1tL3+bE/yuYVaOgGN4fiibG9Cc8MGMrWsZKRvP5Hy/ZUobVfLAPXvpUKM -+nf//MaO6x9F/9TEwIb9rqfoD+bynL1s2LhRwr2ppYZXoOmdS/yhEiXloX4fO//5 -ivC/1zpt6bYaqdA2WAkBHyM24LOm02lJvRV+oq5dFxH0c0YCAEe05QfVLXgb/S/J -TpxfOlabAVomb9+9ESOpEWqCyOo3U3QaSh49FdCUGFnaZHXc4324E/La955dSdez -iLlDKXrdAgMBAAECggEASWNI8eekzxj1xuwdL3EDy14OV34vRt/W/alOgeyTnaRX -9+2qUNtPNn//Ulqkq/sz9CJigKnC3vMep6vuCqnY70QOK3cdKZvtN937Hn8FOKXK -DuB3YEssL7jMgssLIac2I1d2D2yp8QwWjSnKIvieoJ9KO2aQ7Gn1SCJYSxfjNj6b -Z4BBnLgfOZebf2zDnXOnfee35v00zLw6EFyMhdwPNEwy505M32EQLu6qyPllSG4a -srlqRsOMyo5iWEV7P8EBzquaWDB/B9PZWkG9JTokaXPFQJnX6Kn5ha5wcuoKBdVy -R0mgPgtfhpvN2Ott4YQdIuo2PTfpc/Y1cTqRTuKWowKBgQDz9F8CmauFHmzrCp6n -cZcW+Z2kUbjI25qat53G4QHAVIcWhMyQaAi+9dbVAuH9r3f1BWb8TcCJ+ut5fONL -WR4oJpgeG6UVMaF15HqSj2FDic1JzY2jWtbKKiytRXlPCNGeCftQalZzsJtTI0Bl -TqFj32flI+ZsfJR3v+9a6Nr14wKBgQDHptlyggV9TCXtSCfLAbaUJeqOVymTymrr -qMcnYp99jHy7tmZIdmULxkeyF54uAX1/xc+nvSGFIO09rH3nEnZovDnvbFPpiFZb -bNMxmGahW4//boTFSFRxxecknDBcUin0b8YjQER6i4tHtj3qUUjvW/J1XlWzZo1z -cPF4oI6oPwKBgQDw9jaGXf0iHrxcqP+uyq7/XY1NSf8oPmmGWsl4MLXHIHbSUlew -Z2IEJNWPTyqjphbpqO1hVvdQEs1WEXp86Ui1RfHJA2ta9MvTo9tCOmdLC6j/Ng6q -BMbVpzS77Tx2SXKrFJbshixgV1gElXQ83J7jBD8eAQjPrXoEkku80vW8GwKBgGmC -SWP0RoZi2aA+A5mK/DvqlbxHX9eUn1COz0CHJBYrSjfBOuiMePXyAS2iwZs6emIt -3YGdt7stHXL8V0ToQt8yqcNXkjjWLhz+s9V/3qzjQIQSmePQR6Agn/h++iev3DAr -aaBzdDz2xdJOAwZzkoG8K7PO+KdoSNR7GYFQCFPtAoGAFlvGvoX6WvQ47AwmVLgk -gBfe1nruqVyz7kubWsy/V2iAkzMcWUUrcvpZgqAy9pRJlWs1wM91SjtFbZ+/UPwQ -HGCGuclXo89b5uCTYVA0B2PxivY9F+RcQtTJZvTGBGIAC5m1+EqR9pVWY9527WD6 -7/MjOwPWTPT7j0jwBkXTo1w= +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbezv6b+NCPYnm +53V3qsFhvKkb/0R6eGupLTO6eO4ZEKE4RceI5lQqqlk+n4VWxtu5AihGUWSTHlC1 +tKoxsAzGVACdamogBIMvClioFEyu1NccH9pi7AaKDWqTT7CV25dX5zmua4NE6z+D +iWMUmqtV5784Ehpey34GeDYKkDjM+Ciwo3T4w39RC2CkzvwSjcgB6sAWC8lek97M +NnfMyDqhVVm8M1TtHOYs7s6J/Ohl68LOR0K41P28SHi6VQ6aAkt4j57Pa/3Z0vTL +KvOVOiKHwo7s5QkXdMTtB8kyRqkaa1QkACKFarOPyrocBDqC+6CbaZSUC8DAU8aU +vy82nxYJAgMBAAECggEANqqhH4AofNlLO7rk09LfVGBzawsZBiCB5gUlG2q6eGie +7rymF+236Rpk735B8Q1RIt7tzy9997YgdYrUjkzSaQcPAknwj1pWz3rJSit8/LmL ++nD+pWpMMEzgTHQn58DCGR+M6dUWXeyCs9ph0lRBap5lXq8Kw4qzwE2S3qrvtaz8 +qJnTFxdlNXqBZiImL7LXiM+jnRUc03LJSSuIdtvxtbgHmtw60hOaRm1OKXtWPCZp +fVNoNrl7EYobKEzoIj+Cxflbr59GPP5BhERoYZJMqZmNhsK3oFrrew3LTaUe+jG2 +09SKaWsA+qrRuPlcKYqfC6qPcRd4n22TwSme9MxaiwKBgQDPMaLlODkUsFmkOiEG +zJhg19m+D9MqoQCSno+1rRwsrhp4kOwWyX5FroSGfNNhAgRBtdgoKGI/jx4P3ex4 +7+8CbQwc2+63LiuwswqP1ZvFaV1HPx5eeYfmLRAbaQKucHekTwx81iqIueT7AxrE +wb38mpTGcITnKpXLIVI1R6WoswKBgQDAGzDknyIkIwLW9OzTVCJwoNW/njDpK7Ch +c/Cy4z8PW/i1/0eDTlaMKY/3G2TeubGAxrMXJBR9HdlFk7L0fy2qYnPrLFsZFWcw +g0VzXRxR1+JcBetY2k0x393VT3OqxN/nyVDKOycwFq/l4mDIztu+pxhrPgTwfqMI +eupHLnsMUwKBgGRtdL2SMOi8Sdb2bgezp7BZL6uWVA53l6V5wcKXs+5cPWxvImAx +LklsO8RMQNDmf1WyZKGiYWzZXALo2LQN6FXOsW5TlDOp53dwcRAiw6w+U/4ys++r +DJofAY2nqqsOzI8R2cWwsVEwebLJYHI6TnJgIvjElUbPN2gMMKKupbdNAoGAJ9R7 +aqtj1MI9kHvvrlE/YsK2Dqip025vjMoRGcXsCS80feeT2DGh2CW157ISU+uEVgLc +luuwI9DQf5CEBhVoTm9jQVtM+AJsBq7w815WxNFR6WqAxUddwf18bQGwJbP0CIbA +7W0eTuYlSjCJiJj7Dqhuc63EMGjRPKzfbirA8GkCgYEAwPZf7o6X0m2/VOjyVENE +b0+0+vzJogYj/feSOgfeFqq1OyQNs+GK+OdralKdVVCjaXLV5itUWCubKh0TLTRU +6/rzDM3SEq9hxu0Wd7McoA9x4s5NM2bAfES/1rsmDYZ3yGUfCxhjP7uU07M285of +g35nSC+Bb1Uq0Qce00LR1kc= -----END PRIVATE KEY----- diff --git a/scripts/filter-commits-by-author.sh b/scripts/filter-commits-by-author.sh new file mode 100755 index 00000000..63999794 --- /dev/null +++ b/scripts/filter-commits-by-author.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# +# Filter commits by author for commitlint validation +# This script identifies commits between two refs and excludes commits from specified authors +# +# Usage: ./filter-commits-by-author.sh [excluded_authors] +# +# Arguments: +# from_sha: Base commit SHA to start from +# to_sha: Head commit SHA to validate up to +# excluded_authors: Comma-separated list of author emails or names to exclude (optional) +# +# Example: +# ./filter-commits-by-author.sh abc123 def456 "bot@example.com,dependabot[bot]" + +set -e + +FROM_SHA="$1" +TO_SHA="$2" +EXCLUDED_AUTHORS="${3:-}" + +if [ -z "$FROM_SHA" ] || [ -z "$TO_SHA" ]; then + echo "Error: FROM_SHA and TO_SHA are required" + echo "Usage: $0 [excluded_authors]" + exit 1 +fi + +# Get the list of all commits between FROM_SHA and TO_SHA +ALL_COMMITS=$(git rev-list --reverse "${FROM_SHA}..${TO_SHA}") + +if [ -z "$ALL_COMMITS" ]; then + echo "No commits found between $FROM_SHA and $TO_SHA" + exit 0 +fi + +# If no excluded authors are specified, validate all commits +if [ -z "$EXCLUDED_AUTHORS" ]; then + echo "No author filtering specified. Validating all commits:" + for commit in $ALL_COMMITS; do + echo " - $(git log -1 --format='%h %s' "$commit")" + done + echo "" + echo "Running commitlint on commits from $FROM_SHA to $TO_SHA" + npx commitlint --from "$FROM_SHA" --to "$TO_SHA" --verbose + exit 0 +fi + +# Convert comma-separated list to array +IFS=',' read -ra EXCLUDED_ARRAY <<< "$EXCLUDED_AUTHORS" + +# Filter commits by author +FILTERED_COMMITS="" +EXCLUDED_COUNT=0 + +for commit in $ALL_COMMITS; do + AUTHOR=$(git log -1 --format='%ae' "$commit") + AUTHOR_NAME=$(git log -1 --format='%an' "$commit") + + SHOULD_EXCLUDE=false + for excluded in "${EXCLUDED_ARRAY[@]}"; do + # Trim whitespace + excluded=$(echo "$excluded" | xargs) + + # Check if author email or name matches the excluded pattern + if [[ "$AUTHOR" == *"$excluded"* ]] || [[ "$AUTHOR_NAME" == *"$excluded"* ]]; then + SHOULD_EXCLUDE=true + break + fi + done + + if [ "$SHOULD_EXCLUDE" = false ]; then + FILTERED_COMMITS="$FILTERED_COMMITS $commit" + else + echo "Excluding commit $commit from $AUTHOR_NAME <$AUTHOR>" + EXCLUDED_COUNT=$((EXCLUDED_COUNT + 1)) + fi +done + +# Remove leading space +FILTERED_COMMITS=$(echo "$FILTERED_COMMITS" | xargs) + +echo "" +echo "Excluded $EXCLUDED_COUNT commit(s) from authors matching: $EXCLUDED_AUTHORS" +echo "" + +# If no commits remain after filtering, exit successfully +if [ -z "$FILTERED_COMMITS" ]; then + echo "No commits to validate after filtering" + exit 0 +fi + +echo "Validating the following commits:" +for commit in $FILTERED_COMMITS; do + echo " - $(git log -1 --format='%h %s (%an)' "$commit")" +done + +echo "" +echo "Running commitlint on filtered commits..." + +# Validate each filtered commit individually +FAILED=0 +for commit in $FILTERED_COMMITS; do + if ! npx commitlint --from "${commit}~1" --to "$commit" --verbose; then + FAILED=1 + fi +done + +if [ $FAILED -eq 1 ]; then + echo "" + echo "Commitlint validation failed for one or more commits" + exit 1 +fi + +echo "" +echo "All filtered commits passed commitlint validation" +exit 0 diff --git a/scripts/test-filter-commits.sh b/scripts/test-filter-commits.sh new file mode 100755 index 00000000..6b4e8480 --- /dev/null +++ b/scripts/test-filter-commits.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Test script for filter-commits-by-author.sh +# +# This script tests the commit filtering functionality + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FILTER_SCRIPT="$SCRIPT_DIR/filter-commits-by-author.sh" + +echo "Testing filter-commits-by-author.sh" +echo "====================================" +echo "" + +# Test 1: Basic usage check +echo "Test 1: Check script requires FROM_SHA and TO_SHA" +if $FILTER_SCRIPT 2>&1 | grep -q "Error: FROM_SHA and TO_SHA are required"; then + echo "✓ Test 1 passed: Script correctly validates required arguments" +else + echo "✗ Test 1 failed: Script should require FROM_SHA and TO_SHA" + exit 1 +fi +echo "" + +# Test 2: Check with valid commits (will fail commitlint, but should run) +echo "Test 2: Running with valid commit range but no filtering" +if $FILTER_SCRIPT HEAD~2 HEAD "" > /dev/null 2>&1 || [ $? -eq 1 ]; then + echo "✓ Test 2 passed: Script runs with valid commit range" +else + echo "✗ Test 2 failed: Script should run with valid commits" + exit 1 +fi +echo "" + +# Test 3: Filter by author (should exclude copilot commits) +echo "Test 3: Filter commits by author (copilot-swe-agent)" +OUTPUT=$($FILTER_SCRIPT HEAD~2 HEAD "copilot-swe-agent" 2>&1) +if echo "$OUTPUT" | grep -q "Excluding commit" || echo "$OUTPUT" | grep -q "No commits to validate after filtering"; then + echo "✓ Test 3 passed: Author filtering works" +else + echo "✗ Test 3 failed: Author filtering should work" + echo "Output: $OUTPUT" + exit 1 +fi +echo "" + +echo "====================================" +echo "All tests passed!"