From 5b29c37137c67f8a6f7cd9bb6b7eb59ea31d3625 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 11 Jul 2026 20:42:03 -0700 Subject: [PATCH] ci: accept trusted unsigned release merge heads (#104838) --- .../openclaw-release-telegram-qa.yml | 42 +++++++++++++------ ...nclaw-release-telegram-qa-workflow.test.ts | 10 ++++- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/.github/workflows/openclaw-release-telegram-qa.yml b/.github/workflows/openclaw-release-telegram-qa.yml index 7d65f59a351e..428ed0eb9503 100644 --- a/.github/workflows/openclaw-release-telegram-qa.yml +++ b/.github/workflows/openclaw-release-telegram-qa.yml @@ -320,7 +320,7 @@ jobs: trusted_reason="release-tag" break fi - done < <(git -C .candidate for-each-ref --format='%(refname)' refs/tags/v) + done < <(git -C .candidate for-each-ref --format='%(refname)' 'refs/tags/v*') fi fi fi @@ -339,18 +339,27 @@ jobs: -f name="$repository_name" \ -f oid="$candidate_sha" )" - signer="$( + signature_status="$( jq -er \ --arg sha "$candidate_sha" \ '.data.repository.object | - select(.oid == $sha and .signature.isValid == true and .signature.state == "VALID") | - .signature.signer.login' \ + select(.oid == $sha) | + if .signature == null then "missing" + elif .signature.isValid == true and .signature.state == "VALID" and + (.signature.signer.login // "") != "" then "valid" + else "invalid" + end' \ <<<"$signature_json" )" + if [[ "$signature_status" == "invalid" ]]; then + echo "Release candidate ${candidate_sha} has an invalid commit signature." >&2 + exit 1 + fi + signer="$(jq -r '.data.repository.object.signature.signer.login // ""' <<<"$signature_json")" permission_actor="$signer" - if [[ "$signer" == "web-flow" ]]; then + if [[ "$signature_status" == "missing" || "$signer" == "web-flow" ]]; then if [[ "$trusted_reason" != "release-branch-head" || -z "$trusted_release_branch" ]]; then - echo "GitHub web-flow candidates require an exact release branch head." >&2 + echo "Unsigned or GitHub web-flow candidates require an exact release branch head." >&2 exit 1 fi permission_actor="$( @@ -1002,7 +1011,7 @@ jobs: trusted_reason="release-tag" break fi - done < <(git for-each-ref --format='%(refname)' refs/tags/v) + done < <(git for-each-ref --format='%(refname)' 'refs/tags/v*') fi fi fi @@ -1018,18 +1027,27 @@ jobs: -f name="$repository_name" \ -f oid="$candidate_sha" )" - signer="$( + signature_status="$( jq -er \ --arg sha "$candidate_sha" \ '.data.repository.object | - select(.oid == $sha and .signature.isValid == true and .signature.state == "VALID") | - .signature.signer.login' \ + select(.oid == $sha) | + if .signature == null then "missing" + elif .signature.isValid == true and .signature.state == "VALID" and + (.signature.signer.login // "") != "" then "valid" + else "invalid" + end' \ <<<"$signature_json" )" + if [[ "$signature_status" == "invalid" ]]; then + echo "Release candidate ${candidate_sha} has an invalid commit signature." >&2 + exit 1 + fi + signer="$(jq -r '.data.repository.object.signature.signer.login // ""' <<<"$signature_json")" permission_actor="$signer" - if [[ "$signer" == "web-flow" ]]; then + if [[ "$signature_status" == "missing" || "$signer" == "web-flow" ]]; then if [[ "$trusted_reason" != "release-branch-head" || -z "$trusted_release_branch" ]]; then - echo "GitHub web-flow candidates require an exact release branch head." >&2 + echo "Unsigned or GitHub web-flow candidates require an exact release branch head." >&2 exit 1 fi permission_actor="$( diff --git a/test/scripts/openclaw-release-telegram-qa-workflow.test.ts b/test/scripts/openclaw-release-telegram-qa-workflow.test.ts index 3fa2cd3fe0d5..9502a94641f3 100644 --- a/test/scripts/openclaw-release-telegram-qa-workflow.test.ts +++ b/test/scripts/openclaw-release-telegram-qa-workflow.test.ts @@ -207,10 +207,18 @@ function runAdvisoryStatus(overrides: Record = {}) { } describe("release Telegram QA workflow", () => { - it("attributes GitHub web-flow release merges to their exact maintainer merger", () => { + it("attributes GitHub web-flow and unsigned release merges to their exact maintainer merger", () => { const source = readFileSync(WORKFLOW_PATH, "utf8"); expect(source.match(/associatedPullRequests\(first:10\)/gu)).toHaveLength(2); + expect(source.match(/for-each-ref --format='%\(refname\)' 'refs\/tags\/v\*'/gu)).toHaveLength( + 2, + ); + expect(source.match(/if \.signature == null then "missing"/gu)).toHaveLength(2); + expect(source.match(/\$signature_status" == "invalid"/gu)).toHaveLength(2); + expect( + source.match(/\$signature_status" == "missing" \|\| "\$signer" == "web-flow"/gu), + ).toHaveLength(2); expect(source.match(/\.mergeCommit\.oid == \$sha/gu)).toHaveLength(2); expect(source.match(/\.baseRefName == \$base/gu)).toHaveLength(2); expect(source.match(/\.baseRepository\.nameWithOwner == \$repo/gu)).toHaveLength(2);