From eadef6d154c312b4261acf886c1967d80931d485 Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sat, 30 May 2026 12:14:32 -0400 Subject: [PATCH 1/2] fix(ci): authenticate tap push via org GitHub App, not a personal PAT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .github/workflows/homebrew-tap.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index edfcb86e..f06df456 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -70,14 +70,29 @@ jobs: echo "--- generated formula head ---" head -40 out/Formula/pythinker-code.rb + # Mint a short-lived installation token for an org-owned GitHub App that + # has Contents: Read and write on the tap repo. This replaces a personal + # PAT: the App is owned by the org (survives member/org changes), its token + # expires in ~1h (minted fresh each run), and it is scoped to only the tap + # repo. owner/repositories are required because the App must reach a repo + # other than the one this workflow runs in. + - name: Mint GitHub App token for the tap repo + id: app-token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.HOMEBREW_TAP_APP_ID }} + private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }} + owner: ${{ env.TAP_OWNER }} + repositories: ${{ env.TAP_REPO }} + - name: Sync formula into tap repo (handles empty repo on first run) env: PKG_VERSION: ${{ steps.ver.outputs.version }} - TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + TAP_TOKEN: ${{ steps.app-token.outputs.token }} run: | set -euxo pipefail if [ -z "${TAP_TOKEN:-}" ]; then - 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 + 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 exit 1 fi # We do NOT use actions/checkout for the tap repo because on the From 610b3249b2db33e53dd82f98e138c3635c60b7cf Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sat, 30 May 2026 20:12:15 -0400 Subject: [PATCH 2/2] 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. --- .github/workflows/homebrew-tap.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index f06df456..f2efb9e4 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -78,7 +78,7 @@ jobs: # other than the one this workflow runs in. - name: Mint GitHub App token for the tap repo id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: app-id: ${{ secrets.HOMEBREW_TAP_APP_ID }} private-key: ${{ secrets.HOMEBREW_TAP_APP_PRIVATE_KEY }}