From de23f75b90f98550d48964f1676a18def03bf7d2 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 2 Apr 2026 03:14:48 -0400 Subject: [PATCH 1/5] Sigscanner PR scan --- .github/workflows/sigscanner-check.yml | 180 ++++--------------------- 1 file changed, 26 insertions(+), 154 deletions(-) diff --git a/.github/workflows/sigscanner-check.yml b/.github/workflows/sigscanner-check.yml index 3b4caf9..e264f49 100644 --- a/.github/workflows/sigscanner-check.yml +++ b/.github/workflows/sigscanner-check.yml @@ -9,8 +9,7 @@ concurrency: group: ${{ github.workflow }}-pr-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true -permissions: - pull-requests: read +permissions: {} jobs: sigscanner-check: @@ -23,168 +22,41 @@ jobs: PR_NUMBER: ${{ github.event.pull_request.number }} VERIFY_MAX_ATTEMPTS: "3" steps: - - name: "Fetch PR commits" - id: fetch-commits - env: - GH_TOKEN: ${{ github.token }} - run: | - # Fetch all commit hashes and their corresponding committers in this PR - gh api "repos/$REPOSITORY/pulls/$PR_NUMBER/commits" --paginate \ - --jq '.[] | [.sha, (.committer.login // "")] | join(",")' \ - > /tmp/commits_with_committer.csv - - commit_count=$(wc -l < /tmp/commits_with_committer.csv | tr -d ' ') - echo "Found $commit_count commits in PR #$PR_NUMBER" - echo "commit-count=$commit_count" >> "$GITHUB_OUTPUT" - - if [[ $commit_count -eq 0 ]]; then - echo "❌ Unexpected: no commits to verify" - exit 1 - fi - - name: "Sigscanner check" id: sigscanner continue-on-error: true env: SIGSCANNER_URL: ${{ secrets.SIGSCANNER_URL }} SIGSCANNER_API_KEY: ${{ secrets.SIGSCANNER_API_KEY }} - COMMIT_COUNT: ${{ steps.fetch-commits.outputs.commit-count }} run: | - > /tmp/verified_commits.csv - - echo "🔎 Verifying $COMMIT_COUNT commits" - - # Loop through all the commits - # For each commit, query Sigscanner with retry to check if it's verified - # Verified commit hashes with committer username are saved to /tmp/verified_commits.csv - while IFS=, read -r commit_sha committer_username; do - [[ -z "$commit_sha" ]] && continue - - commit_is_verified=false - request_attempt=1 - - while [[ $request_attempt -le $VERIFY_MAX_ATTEMPTS ]]; do - response=$(curl -s --max-time 20 -G \ - -H "X-SIGSCANNER-SECRET: $SIGSCANNER_API_KEY" \ - --data-urlencode "commit=$commit_sha" \ - --data-urlencode "repository=$REPOSITORY" \ - --data-urlencode "author=$committer_username" \ - "$SIGSCANNER_URL") - - res_verified=$(echo "$response" | jq -r '.verified') - res_error=$(echo "$response" | jq -r '.error') - - if [[ "$res_verified" == "true" ]]; then - commit_is_verified=true - break - elif [[ "$res_error" == "null" || "$res_error" == "" ]]; then - # This means the commit is explicitly unverified and shouldn't be retried - break - fi - - [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]] && sleep 15 - request_attempt=$((request_attempt + 1)) - done - - if [[ "$commit_is_verified" == "true" ]]; then - echo "✅ $commit_sha" - echo "$commit_sha,$committer_username" >> /tmp/verified_commits.csv + request_attempt=1 + while [[ $request_attempt -le $VERIFY_MAX_ATTEMPTS ]]; do + response=$(curl -s --max-time 300 -G \ + -H "X-SIGSCANNER-SECRET: $SIGSCANNER_API_KEY" \ + --data-urlencode "pr=$PR_NUMBER" \ + --data-urlencode "repository=$REPOSITORY" \ + "$SIGSCANNER_URL") + + res_verified=$(echo "$response" | jq -r '.verified') + res_unverified_commits=$(echo "$response" | jq '.unverified_commits') + res_error=$(echo "$response" | jq -r '.error') + + if [[ "$res_verified" == "true" ]]; then + echo "✅ All commits verified" + exit 0 + break + elif [[ "$(echo "$response" | jq '(.unverified_commits // []) | length > 0')" == "true" ]]; then + # Non-empty unverified_commits: definitive result, do not retry + echo "❌ Unverified commits:" + echo "$res_unverified_commits" + break else - echo "❌ $commit_sha" + echo "❌ Error: $res_error" fi - done < /tmp/commits_with_committer.csv - verified_commit_count=$(wc -l < /tmp/verified_commits.csv | tr -d ' ') - echo "Verified: $verified_commit_count / $COMMIT_COUNT" - - if [[ $verified_commit_count -eq $COMMIT_COUNT ]]; then - echo "✅ All commits verified" - exit 0 - fi + [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]] && sleep 15 + request_attempt=$((request_attempt + 1)) + done echo "❌ Not all commits verified" exit 1 - - - name: "Sigscanner fallback check" - if: ${{ steps.sigscanner.outcome == 'failure' }} - env: - API_TOKEN: ${{ secrets.SIGSCANNER_API_TOKEN }} - API_URL: ${{ secrets.SIGSCANNER_API_URL }} - COMMIT_COUNT: ${{ steps.fetch-commits.outputs.commit-count }} - run: | - touch /tmp/verified_commits.csv - - # Extract commits failed to verify earlier by comparing the verified commits file - # with the full list of commits - grep -vxFf /tmp/verified_commits.csv /tmp/commits_with_committer.csv \ - > /tmp/pending_commits.csv - - pending_commit_count=$(wc -l < /tmp/pending_commits.csv | tr -d ' ') - - if [[ $pending_commit_count -eq 0 ]]; then - echo "✅ All commits verified" - exit 0 - fi - - echo "🔎 Fallback: verifying $pending_commit_count remaining commits" - - # Loop through all the commits again with retry with the fallback API - while IFS=, read -r commit_sha committer_username; do - [[ -z "$commit_sha" ]] && continue - - commit_is_verified=false - request_attempt=1 - - while [[ $request_attempt -le $VERIFY_MAX_ATTEMPTS ]]; do - body=$(jq -n \ - --arg commit "$commit_sha" \ - --arg repository "$REPOSITORY" \ - --arg author "$committer_username" \ - '{commit: $commit, repository: $repository, author: $author}') - - http_status=$(curl --silent --output /dev/null --write-out '%{http_code}' \ - --max-time 20 -X POST \ - -H "Content-Type: application/json" \ - -H "Authorization: $API_TOKEN" \ - --url "$API_URL" \ - --data "$body") - - case $http_status in - 200) - commit_is_verified=true - break - ;; - 400) - echo "❌ $commit_sha - Bad request" - break - ;; - 403) break ;; - 5??) - [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]] && sleep 15 - ;; - *) - echo "❌ $commit_sha - Unexpected: $http_status" - break - ;; - esac - - request_attempt=$((request_attempt + 1)) - done - - if [[ "$commit_is_verified" == "true" ]]; then - echo "✅ $commit_sha" - echo "$commit_sha,$committer_username" >> /tmp/verified_commits.csv - else - echo "❌ $commit_sha" - fi - done < /tmp/pending_commits.csv - - total_verified_count=$(wc -l < /tmp/verified_commits.csv | tr -d ' ') - echo "Verified: $total_verified_count / $COMMIT_COUNT" - - if [[ $total_verified_count -ne $COMMIT_COUNT ]]; then - echo "❌ Not all commits verified by fallback" - exit 1 - fi - - echo "✅ All commits verified" From 9bc53641296c256df3a1e27ea804acf314942005 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 2 Apr 2026 03:20:10 -0400 Subject: [PATCH 2/5] fix --- .github/workflows/sigscanner-check.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/sigscanner-check.yml b/.github/workflows/sigscanner-check.yml index e264f49..be70350 100644 --- a/.github/workflows/sigscanner-check.yml +++ b/.github/workflows/sigscanner-check.yml @@ -24,7 +24,6 @@ jobs: steps: - name: "Sigscanner check" id: sigscanner - continue-on-error: true env: SIGSCANNER_URL: ${{ secrets.SIGSCANNER_URL }} SIGSCANNER_API_KEY: ${{ secrets.SIGSCANNER_API_KEY }} From c5518be3ec6f2eb0b99766786e74f3a4c02ff8b8 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 2 Apr 2026 03:22:35 -0400 Subject: [PATCH 3/5] Update .github/workflows/sigscanner-check.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/sigscanner-check.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/sigscanner-check.yml b/.github/workflows/sigscanner-check.yml index be70350..8408bd3 100644 --- a/.github/workflows/sigscanner-check.yml +++ b/.github/workflows/sigscanner-check.yml @@ -43,7 +43,6 @@ jobs: if [[ "$res_verified" == "true" ]]; then echo "✅ All commits verified" exit 0 - break elif [[ "$(echo "$response" | jq '(.unverified_commits // []) | length > 0')" == "true" ]]; then # Non-empty unverified_commits: definitive result, do not retry echo "❌ Unverified commits:" From 5c121c7732ae5c7609b74e7b4f70100534b928dd Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 2 Apr 2026 16:41:32 -0400 Subject: [PATCH 4/5] Make pretty --- .github/workflows/sigscanner-check.yml | 35 ++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/workflows/sigscanner-check.yml b/.github/workflows/sigscanner-check.yml index 8408bd3..820d4a7 100644 --- a/.github/workflows/sigscanner-check.yml +++ b/.github/workflows/sigscanner-check.yml @@ -20,6 +20,7 @@ jobs: env: REPOSITORY: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} + PR_COMMIT_COUNT: ${{ github.event.pull_request.commits }} VERIFY_MAX_ATTEMPTS: "3" steps: - name: "Sigscanner check" @@ -28,16 +29,36 @@ jobs: SIGSCANNER_URL: ${{ secrets.SIGSCANNER_URL }} SIGSCANNER_API_KEY: ${{ secrets.SIGSCANNER_API_KEY }} run: | + echo "Verifying $PR_COMMIT_COUNT commits..." request_attempt=1 + total_start=$SECONDS while [[ $request_attempt -le $VERIFY_MAX_ATTEMPTS ]]; do - response=$(curl -s --max-time 300 -G \ + echo "::group::Attempt $request_attempt/$VERIFY_MAX_ATTEMPTS — calling Sigscanner API..." + attempt_start=$SECONDS + + http_code=$(curl -s -o /tmp/sigscanner_response --max-time 300 -w '%{http_code}' -G \ -H "X-SIGSCANNER-SECRET: $SIGSCANNER_API_KEY" \ --data-urlencode "pr=$PR_NUMBER" \ --data-urlencode "repository=$REPOSITORY" \ "$SIGSCANNER_URL") + response=$(cat /tmp/sigscanner_response) + + elapsed=$(( SECONDS - attempt_start )) + echo "API responded in ${elapsed}s (HTTP $http_code)" + echo "::endgroup::" + + if [[ "$http_code" != "200" ]]; then + echo "❌ Sigscanner API returned HTTP $http_code (attempt $request_attempt, ${elapsed}s)" + if [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]]; then + echo "⏳ Retrying in 15s..." + sleep 15 + fi + request_attempt=$((request_attempt + 1)) + continue + fi res_verified=$(echo "$response" | jq -r '.verified') - res_unverified_commits=$(echo "$response" | jq '.unverified_commits') + res_error=$(echo "$response" | jq -r '.error') if [[ "$res_verified" == "true" ]]; then @@ -46,15 +67,19 @@ jobs: elif [[ "$(echo "$response" | jq '(.unverified_commits // []) | length > 0')" == "true" ]]; then # Non-empty unverified_commits: definitive result, do not retry echo "❌ Unverified commits:" - echo "$res_unverified_commits" + echo "$response" | jq -r '.unverified_commits[] | " - \(.)"' break else echo "❌ Error: $res_error" fi - [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]] && sleep 15 + if [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]]; then + echo "⏳ Retrying in 15s..." + sleep 15 + fi request_attempt=$((request_attempt + 1)) done - echo "❌ Not all commits verified" + total_elapsed=$(( SECONDS - total_start )) + echo "❌ Not all commits verified (total time: ${total_elapsed}s)" exit 1 From 09e4b4ac9ba3c1fae347bcefecbd8a78ce660a0f Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 2 Apr 2026 17:34:26 -0400 Subject: [PATCH 5/5] Make pretty --- .github/workflows/sigscanner-check.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sigscanner-check.yml b/.github/workflows/sigscanner-check.yml index 820d4a7..3e96429 100644 --- a/.github/workflows/sigscanner-check.yml +++ b/.github/workflows/sigscanner-check.yml @@ -49,6 +49,7 @@ jobs: if [[ "$http_code" != "200" ]]; then echo "❌ Sigscanner API returned HTTP $http_code (attempt $request_attempt, ${elapsed}s)" + echo "If this PR has many commits, Sigscanner might time out. Try running the workflow again. Sigscanner will pick up from the last verified commit." if [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]]; then echo "⏳ Retrying in 15s..." sleep 15 @@ -57,8 +58,18 @@ jobs: continue fi - res_verified=$(echo "$response" | jq -r '.verified') + if ! echo "$response" | jq empty >/dev/null 2>&1; then + echo "❌ HTTP 200 but body is not valid JSON (attempt $request_attempt, ${elapsed}s)" + echo + if [[ $request_attempt -lt $VERIFY_MAX_ATTEMPTS ]]; then + echo "⏳ Retrying in 15s..." + sleep 15 + fi + request_attempt=$((request_attempt + 1)) + continue + fi + res_verified=$(echo "$response" | jq -r '.verified') res_error=$(echo "$response" | jq -r '.error') if [[ "$res_verified" == "true" ]]; then