From 2e47e9cd566467de9f9260412fa62e7c67e31fff Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 29 Jul 2026 10:04:12 -0400 Subject: [PATCH] docs: correct the HOMEBREW_TOKEN type and scope BUILDING.md called for a fine-grained PAT scoped to Homebrew/homebrew-cask. That token cannot exist: a fine-grained PAT's repository selector only lists repos owned by the resource owner, so a repo you do not own can never be selected, and Homebrew's API layer authorises against classic OAuth scopes (x-oauth-scopes) which fine-grained tokens do not emit. brew bump-cask-pr forks homebrew-cask into the TOKEN OWNER's account, pushes a branch there, and opens the PR upstream. Homebrew declares the requirement as CREATE_ISSUE_FORK_OR_PR_SCOPES = ["repo"] in utils/github.rb, so it is a classic PAT with the `repo` scope. Add the create-token link and call out that `repo` grants write to every repo the account can reach -- including this one -- so the CI secret should belong to a dedicated bot account whose only asset is the fork. --- BUILDING.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index 120a23172a..6cfc3ee639 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -529,9 +529,32 @@ their token type and scope: | Secret | Purpose | Scope | |---|---|---| -| `HOMEBREW_TOKEN` | Bump Homebrew cask | Fine-grained PAT — `Homebrew/homebrew-cask` only — `Contents: write` + `Pull requests: write` — 90d expiry | +| `HOMEBREW_TOKEN` | Bump Homebrew cask | **Classic** PAT — `repo` scope — 90d expiry (dedicated bot account strongly preferred; see below) | | `WINGET_TOKEN` | Submit Winget manifests | Classic PAT — `public_repo` — 90d expiry (dedicated bot account preferred; `vedantmgoyal9/winget-releaser` does not support fine-grained) | +**Why `HOMEBREW_TOKEN` must be a classic PAT, not fine-grained.** `brew +bump-cask-pr` forks `Homebrew/homebrew-cask` **into the token owner's account** +(`POST /repos/Homebrew/homebrew-cask/forks`), pushes a branch to that fork, and +opens the PR upstream. Two consequences: + +- A fine-grained PAT cannot express this. Its "Repository access" selector only + lists repos owned by the resource owner, so `Homebrew/homebrew-cask` can never + be selected — and Homebrew's API layer authorises against classic OAuth scopes + (`x-oauth-scopes`), which fine-grained tokens do not emit. +- Homebrew declares the requirement in source as + `CREATE_ISSUE_FORK_OR_PR_SCOPES = ["repo"]` (`utils/github.rb`), so the scope + is `repo`. + +Create it at +. + +**Use a dedicated bot account.** The `repo` scope grants write to *every* +repository the account can reach — including `vitorpamplona/amethyst` itself. A +bot account whose only asset is a fork of `homebrew-cask` bounds the blast +radius of a leaked CI secret to that fork. (`WINGET_TOKEN` has the same +property, which is why a bot account is already recommended for it.) The bot +must have forked `Homebrew/homebrew-cask`, or be able to. + Rotate both on a 90-day cadence. Owner: assigned via `RELEASE_OPS.md` or equivalent issue tracker. On rotation, paste the new token and run `gh workflow run bump-homebrew.yml -f tag=` to verify