From aaddaf529ffe57558dffe91bc3ac4d6836c08a67 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Thu, 24 Sep 2026 09:26:13 +0000 Subject: [PATCH] Grant the distribute job the permissions it asks for A reusable workflow can only hold a subset of its caller's permissions. submit-packages.yml requests `pull-requests: write` to open the PR carrying the refreshed distribution/ manifests, but release.yml granted only `contents: write`, so the push would succeed and the PR creation be denied. The script also swallowed that denial with a bare `||`, reporting success with no PR behind it. It now distinguishes an already-open PR, which is expected on a re-run, from a real failure, which exits non-zero. A silent success here is precisely how this pipeline spent three months looking healthy while publishing nothing. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/release.yml | 6 ++++++ scripts/open-distribution-pr.sh | 24 ++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5020000..60a5ef2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,8 +9,14 @@ on: description: 'Version to release (e.g. 0.1.0)' required: true +# A called workflow can only ever hold a subset of its caller's permissions, so +# the distribute job's `pull-requests: write` has to be granted here too — it +# opens the PR carrying the refreshed distribution/ manifests. Without this the +# push succeeds and `gh pr create` is denied, which the script swallows, so the +# branch would appear with no PR behind it. permissions: contents: write + pull-requests: write jobs: # 1) Create the GitHub Release (draft) up front so each per-platform build job diff --git a/scripts/open-distribution-pr.sh b/scripts/open-distribution-pr.sh index 3da6cf3..e99f3e5 100755 --- a/scripts/open-distribution-pr.sh +++ b/scripts/open-distribution-pr.sh @@ -37,13 +37,29 @@ else git push origin "${BRANCH}" fi -# `gh pr create` fails if one is already open for the branch, which is fine. -gh pr create \ +# An already-open PR for this branch is fine and expected on a re-run. Anything +# else — a denied token, a missing base — is a real failure and must not be +# swallowed: a silent success here is precisely how this pipeline went three +# months looking healthy while publishing nothing. +set +e +OUT="$(gh pr create \ --base main \ --head "${BRANCH}" \ --title "chore(distribution): refresh manifests for v${VERSION}" \ --body "Automated manifest refresh from the release pipeline for v${VERSION}. Version strings and sha256 checksums are rewritten from the published release -assets by \`scripts/submit-packages.mjs\`." \ - || echo "a PR for ${BRANCH} already exists; branch updated in place" +assets by \`scripts/submit-packages.mjs\`." 2>&1)" +RC=$? +set -e + +echo "${OUT}" + +if [ "${RC}" -ne 0 ]; then + if echo "${OUT}" | grep -qi "already exists"; then + echo "a PR for ${BRANCH} already exists; branch updated in place" + else + echo "gh pr create failed for ${BRANCH}" >&2 + exit "${RC}" + fi +fi