Skip to content

Commit b321a07

Browse files
authored
fix(ci): authenticate tap push via org GitHub App, not a personal PAT (#28)
* fix(ci): authenticate tap push via org GitHub App, not a personal PAT The homebrew-tap workflow pushes the generated formula to the separate TechMatrix-labs/homebrew-pythinker repo, which the default GITHUB_TOKEN cannot write to, so it used a personal PAT in HOMEBREW_TAP_TOKEN. That PAT broke on the org migration and again on re-issue (authenticated but lacked Contents: write -> 403 on push), freezing the tap at 0.25.0. Replace it with a short-lived token minted at runtime from an org-owned GitHub App (actions/create-github-app-token) that has Contents: Read and write on the tap repo. The App is owned by the org (survives member/org changes), its installation token expires in ~1h and is minted fresh each run, and owner/repositories scope it to only the tap repo. Deploy keys — the simpler robust option — are disabled org-wide, so the App is the frictionless path that needs no org policy change. Requires two secrets on this repo: HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY. The old HOMEBREW_TAP_TOKEN secret is no longer referenced and can be deleted. * fix(ci): pin create-github-app-token to a commit SHA This action mints an installation token from the tap App's private key, so pin it to an immutable commit (v2.2.2) rather than the movable v2 tag to remove the supply-chain risk of a retagged release exfiltrating the key. Addresses CodeRabbit review on #28.
1 parent 707817d commit b321a07

1 file changed

Lines changed: 17 additions & 2 deletions

File tree

.github/workflows/homebrew-tap.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,29 @@ jobs:
7070
echo "--- generated formula head ---"
7171
head -40 out/Formula/pythinker-code.rb
7272
73+
# Mint a short-lived installation token for an org-owned GitHub App that
74+
# has Contents: Read and write on the tap repo. This replaces a personal
75+
# PAT: the App is owned by the org (survives member/org changes), its token
76+
# expires in ~1h (minted fresh each run), and it is scoped to only the tap
77+
# repo. owner/repositories are required because the App must reach a repo
78+
# other than the one this workflow runs in.
79+
- name: Mint GitHub App token for the tap repo
80+
id: app-token
81+
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
82+
with:
83+
app-id: ${{ secrets.HOMEBREW_TAP_APP_ID }}
84+
private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }}
85+
owner: ${{ env.TAP_OWNER }}
86+
repositories: ${{ env.TAP_REPO }}
87+
7388
- name: Sync formula into tap repo (handles empty repo on first run)
7489
env:
7590
PKG_VERSION: ${{ steps.ver.outputs.version }}
76-
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
91+
TAP_TOKEN: ${{ steps.app-token.outputs.token }}
7792
run: |
7893
set -euxo pipefail
7994
if [ -z "${TAP_TOKEN:-}" ]; then
80-
echo "::error::HOMEBREW_TAP_TOKEN secret is empty or unset — cannot push to ${TAP_OWNER}/${TAP_REPO}. Add a fine-grained PAT (Contents: Read and write on the tap repo) as the HOMEBREW_TAP_TOKEN secret, then re-run this workflow." >&2
95+
echo "::error::No tap token available — the GitHub App token mint produced an empty value. Confirm the HOMEBREW_TAP_APP_ID and HOMEBREW_TAP_APP_PRIVATE_KEY secrets are set and the App is installed on ${TAP_OWNER}/${TAP_REPO} with Contents: Read and write, then re-run this workflow." >&2
8196
exit 1
8297
fi
8398
# We do NOT use actions/checkout for the tap repo because on the

0 commit comments

Comments
 (0)