ci: call homebrew-bump as reusable workflow instead of PAT event propagation #53

Merged
razvandimescu merged 1 commits from ci/release-workflow-call-homebrew-bump into main 2026-04-10 04:33:48 +08:00
razvandimescu commented 2026-04-10 04:30:12 +08:00 (Migrated from github.com)

Why

PR #44 swapped GITHUB_TOKEN for HOMEBREW_TAP_GITHUB_TOKEN on action-gh-release so that the release: published event would propagate to homebrew-bump.yml. The reasoning was correct — GitHub Actions deliberately does not propagate events triggered by GITHUB_TOKEN — but the implementation conflated two unrelated scopes into one token, and that bit us on the v0.10.2 cut.

HOMEBREW_TAP_GITHUB_TOKEN is a fine-grained PAT scoped only to razvandimescu/homebrew-tap (because that's all homebrew-bump.yml originally needed: clone + push the tap repo). It has zero access to razvandimescu/numa, so when action-gh-release tried to create a release on numa, GitHub returned:

⚠️ GitHub release failed with status: 403
{"message":"Resource not accessible by personal access token", ...}

v0.10.2 had to be recovered manually via gh release create from a user PAT. v0.10.0 and v0.10.1 both worked fine — because PR #44 was merged after v0.10.1 was tagged, v0.10.2 was the first release to actually exercise the new code path.

Fix

Sidestep the event-propagation rule entirely by invoking homebrew-bump.yml directly as a reusable workflow via workflow_call. Each token then does exactly what its scope permits:

  • GITHUB_TOKEN creates the release on numa (default contents: write)
  • HOMEBREW_TAP_GITHUB_TOKEN pushes to homebrew-tap (unchanged)

release.yml

  • Drop the token: override on action-gh-release → reverts to GITHUB_TOKEN default (which v0.10.0 and v0.10.1 used successfully).
  • Add a new bump-homebrew job:
    bump-homebrew:
      needs: release
      uses: ./.github/workflows/homebrew-bump.yml
      with:
        version: ${{ github.ref_name }}
      secrets: inherit
    

homebrew-bump.yml

  • Add workflow_call trigger with a version input.
  • Remove the release: published trigger — no longer needed since we invoke directly.
  • Keep workflow_dispatch for manual recovery.
  • Collapse version determination to a single inputs.version read (the branch on github.event_name is gone).

Benefits over #44

  1. No event-propagation dependencyneeds: release is a hard dependency; release: published was a soft hope that events would fire.
  2. Each token stays minimally scoped — principle of least privilege, and no "why does the tap push token also need numa contents:write?" confusion.
  3. Failures are visible in one run — the tap bump appears as a child job in the release workflow, not a separate "why didn't this fire?" mystery.
  4. Manual recovery still worksworkflow_dispatch trigger retained for gh workflow run homebrew-bump.yml -f version=x.y.z.

Test plan

  • CI green on the PR (linter only — no behavior to test until next release)
  • First real release (v0.10.3+) verifies end-to-end that the tap auto-bumps without manual intervention and without needing HOMEBREW_TAP_GITHUB_TOKEN scope expansion

What this affects

  • v0.10.0 / v0.10.1 / v0.10.2 (shipped): not affected
  • v0.10.3 and later: release workflow uses default GITHUB_TOKEN for release creation, calls homebrew-bump as a reusable workflow for the tap update
  • HOMEBREW_TAP_GITHUB_TOKEN PAT scope: unchanged — still only needs access to razvandimescu/homebrew-tap

🤖 Generated with Claude Code

## Why PR #44 swapped `GITHUB_TOKEN` for `HOMEBREW_TAP_GITHUB_TOKEN` on `action-gh-release` so that the `release: published` event would propagate to `homebrew-bump.yml`. The reasoning was correct — GitHub Actions deliberately does not propagate events triggered by `GITHUB_TOKEN` — but the implementation conflated two unrelated scopes into one token, and that bit us on the v0.10.2 cut. `HOMEBREW_TAP_GITHUB_TOKEN` is a fine-grained PAT scoped **only** to `razvandimescu/homebrew-tap` (because that's all `homebrew-bump.yml` originally needed: clone + push the tap repo). It has zero access to `razvandimescu/numa`, so when `action-gh-release` tried to create a release on `numa`, GitHub returned: ``` ⚠️ GitHub release failed with status: 403 {"message":"Resource not accessible by personal access token", ...} ``` v0.10.2 had to be recovered manually via `gh release create` from a user PAT. v0.10.0 and v0.10.1 both worked fine — because PR #44 was merged **after** v0.10.1 was tagged, v0.10.2 was the first release to actually exercise the new code path. ## Fix Sidestep the event-propagation rule entirely by invoking `homebrew-bump.yml` directly as a **reusable workflow** via `workflow_call`. Each token then does exactly what its scope permits: - `GITHUB_TOKEN` creates the release on `numa` (default `contents: write`) - `HOMEBREW_TAP_GITHUB_TOKEN` pushes to `homebrew-tap` (unchanged) ### release.yml - Drop the `token:` override on `action-gh-release` → reverts to `GITHUB_TOKEN` default (which v0.10.0 and v0.10.1 used successfully). - Add a new `bump-homebrew` job: ```yaml bump-homebrew: needs: release uses: ./.github/workflows/homebrew-bump.yml with: version: ${{ github.ref_name }} secrets: inherit ``` ### homebrew-bump.yml - Add `workflow_call` trigger with a `version` input. - Remove the `release: published` trigger — no longer needed since we invoke directly. - Keep `workflow_dispatch` for manual recovery. - Collapse version determination to a single `inputs.version` read (the branch on `github.event_name` is gone). ## Benefits over #44 1. **No event-propagation dependency** — `needs: release` is a hard dependency; `release: published` was a soft hope that events would fire. 2. **Each token stays minimally scoped** — principle of least privilege, and no "why does the tap push token also need `numa` contents:write?" confusion. 3. **Failures are visible in one run** — the tap bump appears as a child job in the release workflow, not a separate "why didn't this fire?" mystery. 4. **Manual recovery still works** — `workflow_dispatch` trigger retained for `gh workflow run homebrew-bump.yml -f version=x.y.z`. ## Test plan - [ ] CI green on the PR (linter only — no behavior to test until next release) - [ ] First real release (v0.10.3+) verifies end-to-end that the tap auto-bumps without manual intervention and without needing `HOMEBREW_TAP_GITHUB_TOKEN` scope expansion ## What this affects - **v0.10.0 / v0.10.1 / v0.10.2 (shipped)**: not affected - **v0.10.3 and later**: release workflow uses default `GITHUB_TOKEN` for release creation, calls homebrew-bump as a reusable workflow for the tap update - **`HOMEBREW_TAP_GITHUB_TOKEN` PAT scope**: unchanged — still only needs access to `razvandimescu/homebrew-tap` 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.