Repository navigation
Conversation
The tap update failed because the user PAT lacked CreatePullRequest. Mint a scoped App token for homebrew-tap instead (SRE-149).
Use the shared dualentry-ci App client ID and private key names.
Replace the personal access token previously required for cross-repo writes.
msn0
left a comment
There was a problem hiding this comment.
- Issue Details
This PR implements SRE-149: replacing the personal access token (HOMEBREW_TAP_TOKEN) with a scoped GitHub App installation token for updating the Homebrew tap on release.
Problem: The PAT lacked CreatePullRequest permission, causing tap update failures when main is protected (requires PR + review).
Solution: Mint a scoped dualentry-ci App token with contents: write and pull-requests: write permissions.
- Standards
No violations of documented standards. The implementation follows GitHub Actions best practices:
- Job-level
permissions: {}correctly resets inherited permissions before granting specific ones (principle of least privilege) - SHA-pinned action version ensures reproducibility
- Added
set -euo pipefailimproves shell safety - Environment variable handling is clean (no unnecessary exports or conditionals)
- Spec Compliance
Implemented:
- ✅ GitHub App token creation via
actions/create-github-app-token@v3.2.0 - ✅ References
DUALENTRY_CI_APP_CLIENT_IDandDUALENTRY_CI_APP_PRIVATE_KEY - ✅ Grants minimal permissions:
contents: write,pull-requests: write - ✅ Scopes token to
homebrew-taprepository - ✅ Uses token for git clone and
gh pr create/mergeoperations - ✅ Removes
TAP_TOKENsecret reference
Deferred per spec plan: The ticket notes HOMEBREW_TAP_TOKEN removal as a follow-up step ("Next: ... merge PR, smoke-test a release, delete HOMEBREW_TAP_TOKEN"). This is acceptable; the PR focuses on workflow implementation.
- Security & Quality
- Token scoping is correct: limited to one repository, specific permissions only
- No secrets logged or exposed in command output
- Git clone uses standard
x-access-tokenauthentication pattern - Merge fallback logic preserved: attempts direct merge, then auto-merge, then warns on manual intervention
- Change is focused and minimal (19 insertions, 6 deletions to one file)
- Detailed Changes
.github/workflows/release.yml:
- Added explicit comment clarifying why App token is required (cross-repo write)
- Added
Create GitHub App tokenstep with proper scoping - Replaced
env.TAP_TOKENreferences withsteps.app-token.outputs.tokenviaGH_TOKEN - Removed conditional
if: ${{ env.TAP_TOKEN != '' }}(always runs now; App token auto-expires per job) - Removed unnecessary
export GH_TOKEN="$TAP_TOKEN"line (env block is sufficient) - Added
set -euo pipefailfor safer shell execution - Updated comment to reflect new App token workflow
- Test Coverage & Verification
The PR includes a test plan in the description:
- Publish or re-run a release and confirm the tap formula PR opens
- Remove the obsolete
HOMEBREW_TAP_TOKENrepository secret
No automation tests are required for workflow-only changes; manual release smoke-test is appropriate.
- Risks & Mitigations
Risk: App token generation fails if DUALENTRY_CI_APP_CLIENT_ID or DUALENTRY_CI_APP_PRIVATE_KEY are not set.
Mitigation: Workflow will fail with clear error message; secrets are already configured per ticket ("App is created and installed").
Risk: homebrew-tap repository does not have the App installed.
Mitigation: Ticket confirms installation: "App dualentry-ci created and installed (selected repos)."
- Readiness
Blockers: None
Ready for merge: ✅ Yes
The implementation correctly replaces PAT-based authentication with a scoped GitHub App token, improves shell safety, and maintains backward-compatible merge behavior. The deferred secret cleanup aligns with the ticket's phased plan.
Summary
Test plan
HOMEBREW_TAP_TOKENrepository secret