Skip to content

Commit b666509

Browse files
committed
docs(ci): add homebrew tap token recovery and fail-fast guidance
1 parent dd4dc16 commit b666509

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

.github/workflows/homebrew-tap-pr.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
HOMEBREW_TAP_REPO: smorinlabs/homebrew-tap
2727
TAP_REPO_DIR: ${{ github.workspace }}/homebrew-tap
2828
HOMEBREW_SOURCE_JSON: ${{ github.workspace }}/.homebrew/source.json
29+
HOMEBREW_TOKEN_DOC_SECTION: "RELEASING.md -> Reset HOMEBREW_TAP_GITHUB_TOKEN (step-by-step)"
2930
steps:
3031
- name: Resolve tag
3132
id: tag
@@ -64,6 +65,73 @@ jobs:
6465
TAG="${{ steps.tag.outputs.tag }}" \
6566
HOMEBREW_SOURCE_JSON="$HOMEBREW_SOURCE_JSON"
6667
68+
- name: Validate tap token permissions
69+
shell: bash
70+
env:
71+
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
72+
run: |
73+
if [[ -z "${HOMEBREW_TAP_GITHUB_TOKEN}" ]]; then
74+
echo "::error::Missing secret HOMEBREW_TAP_GITHUB_TOKEN."
75+
echo "::error::Fix by following: ${HOMEBREW_TOKEN_DOC_SECTION}"
76+
exit 1
77+
fi
78+
79+
API_URL="https://api.github.com/repos/${HOMEBREW_TAP_REPO}"
80+
HTTP_CODE="$(curl -sS -o /tmp/homebrew-tap-repo.json -w "%{http_code}" \
81+
-H "Authorization: Bearer ${HOMEBREW_TAP_GITHUB_TOKEN}" \
82+
-H "Accept: application/vnd.github+json" \
83+
"${API_URL}")"
84+
85+
python3 - "${HTTP_CODE}" <<'PY'
86+
import json
87+
import os
88+
import sys
89+
90+
code = int(sys.argv[1])
91+
repo = os.environ["HOMEBREW_TAP_REPO"]
92+
doc = os.environ["HOMEBREW_TOKEN_DOC_SECTION"]
93+
payload_path = "/tmp/homebrew-tap-repo.json"
94+
95+
payload = {}
96+
try:
97+
with open(payload_path, "r", encoding="utf-8") as fh:
98+
payload = json.load(fh)
99+
except Exception:
100+
payload = {}
101+
102+
def emit_error(message: str) -> None:
103+
print(f"::error::{message}")
104+
105+
if code != 200:
106+
emit_error(
107+
f"HOMEBREW_TAP_GITHUB_TOKEN cannot access {repo} (GitHub API HTTP {code})."
108+
)
109+
emit_error(
110+
"Expected fine-grained token scope: repo access to smorinlabs/homebrew-tap with "
111+
"Contents: Read and write and Pull requests: Read and write."
112+
)
113+
emit_error(f"Fix by following: {doc}")
114+
gh_message = payload.get("message")
115+
if gh_message:
116+
emit_error(f"GitHub response: {gh_message}")
117+
raise SystemExit(1)
118+
119+
permissions = payload.get("permissions") or {}
120+
if permissions and not permissions.get("push", False):
121+
emit_error(
122+
f"HOMEBREW_TAP_GITHUB_TOKEN can read {repo} but cannot push "
123+
"(permissions.push=false)."
124+
)
125+
emit_error(
126+
"Expected fine-grained token scope: Contents: Read and write and "
127+
"Pull requests: Read and write."
128+
)
129+
emit_error(f"Fix by following: {doc}")
130+
raise SystemExit(1)
131+
132+
print(f"Token validation passed for {repo}.")
133+
PY
134+
67135
- name: Checkout tap repository
68136
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
69137
with:
@@ -95,7 +163,16 @@ jobs:
95163
env:
96164
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
97165
run: |
166+
set +e
98167
make homebrew-open-tap-pr \
99168
TAG="${{ steps.tag.outputs.tag }}" \
100169
TAP_REPO_DIR="$TAP_REPO_DIR" \
101170
HOMEBREW_TAP_REPO="$HOMEBREW_TAP_REPO"
171+
RC="$?"
172+
set -e
173+
174+
if [[ "$RC" -ne 0 ]]; then
175+
echo "::error::Failed to open/update tap PR. This can happen when HOMEBREW_TAP_GITHUB_TOKEN is expired or missing repo permissions."
176+
echo "::error::Fix by following: ${HOMEBREW_TOKEN_DOC_SECTION}"
177+
exit "$RC"
178+
fi

RELEASING.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,39 @@ Automation equivalent:
293293

294294
- `.github/workflows/homebrew-tap-pr.yml` runs on `release.published` and can be retried with `workflow_dispatch`.
295295

296+
## Reset HOMEBREW_TAP_GITHUB_TOKEN (step-by-step)
297+
298+
Use a fine-grained PAT for this (this is `HOMEBREW_TAP_GITHUB_TOKEN`, not `HOMEBREW_GITHUB_API_TOKEN`).
299+
300+
1. Go to GitHub: Profile photo -> `Settings` -> `Developer settings` -> `Personal access tokens` -> `Fine-grained tokens` -> `Generate new token`.
301+
2. Set:
302+
- `Resource owner`: `smorinlabs`
303+
- `Repository access`: `Only select repositories`
304+
- Select repo: `smorinlabs/homebrew-tap`
305+
3. Under **Repository permissions**, set:
306+
- `Contents`: `Read and write`
307+
- `Pull requests`: `Read and write`
308+
4. Set expiration (recommended: short, e.g. 90 days), then click `Generate token`.
309+
5. Copy the token immediately (you won’t be able to view it again).
310+
6. If GitHub shows token status `pending` (org approval enabled), approve it in org token settings.
311+
7. Add it to `smorinlabs/envgen` secrets:
312+
- Repo -> `Settings` -> `Secrets and variables` -> `Actions` -> `New repository secret`
313+
- Name: `HOMEBREW_TAP_GITHUB_TOKEN`
314+
- Value: token from step 5
315+
8. Test it:
316+
- `gh workflow run homebrew-tap-pr.yml -R smorinlabs/envgen -f tag=v1.0.1`
317+
318+
CLI shortcut for step 7:
319+
320+
```bash
321+
printf %s "$TOKEN" | gh secret set HOMEBREW_TAP_GITHUB_TOKEN -R smorinlabs/envgen
322+
```
323+
324+
Docs:
325+
326+
- [Managing personal access tokens](https://docs.github.com/enterprise-cloud@latest/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
327+
- [Fine-grained PAT permission model](https://docs.github.com/en/rest/overview/permissions-required-for-fine-grained-personal-access-tokens)
328+
296329
## Failure modes
297330

298331
- Missing release section for tagging:
@@ -313,6 +346,9 @@ Automation equivalent:
313346
- Partial update on bump failure:
314347
- A failed bump can leave version/changelog edits before later steps complete.
315348
- Recovery: run `make sync-lockfile` and retry the bump after fixing the reported error.
349+
- Homebrew tap token auth/permission errors:
350+
- Symptom: workflow step `Validate tap token permissions` fails with `::error::` output.
351+
- Fix: follow `Reset HOMEBREW_TAP_GITHUB_TOKEN (step-by-step)` in this document.
316352

317353
## Emergency fallback (temporary)
318354

0 commit comments

Comments
 (0)