Skip to content

Scope the release app token to what releaseo needs - #6266

Merged
ChrisJBurns merged 1 commit into
mainfrom
harden-release-pr-token
Aug 10, 2026
Merged

Scope the release app token to what releaseo needs#6266
ChrisJBurns merged 1 commit into
mainfrom
harden-release-pr-token

Conversation

@ChrisJBurns

@ChrisJBurns ChrisJBurns commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Second of the release-workflow changes tracked in #6253, after #6263.

Summary

  • The app token carried every permission its installation holds. actions/create-github-app-token with no permission-* inputs mints a token scoped to the whole installation. This one is handed to releaseo, which pushes a branch and opens a pull request — so contents: write and pull-requests: write are all it needs.
  • Three summary-step expressions bound through env: rather than interpolated into the shell. No behaviour change.

create-release-pr.yml goes from 4 findings to 1 — github-app and all three template-injection clear. The remaining artipacked is deliberately untouched, see below.

✅ Verified by a real dispatch run

permission-* inputs can only narrow a token, never grant — so if the RELEASE_APP installation did not hold contents: write or pull-requests: write, the token step would fail and no release PR could ever be created. Reading installation permissions needs admin:org, which I do not have, so this was settled by observation instead.

create-release-pr.yml is workflow_dispatch, so it was run from this branch (run 31419393149) with bump_type=patch:

Step Result What it establishes
Generate release app token The app installation does hold both permissions — the narrowing cannot fail
Create Release PR The narrowed token is sufficient: releaseo pushed the branch and opened the pull request with it
Summary The env: binding renders correctly

It produced a genuine release pull request — #6267, Release v0.42.2, touching VERSION, both Chart.yaml files, both chart README.md files and values.yaml. That is the point: the whole path ran under the reduced token, not just the token step. It has been closed and its branch deleted, and main's VERSION is confirmed still 0.42.1.

Of the four release workflows this is the only one that can be exercised at all, which is why it was chosen to go early.

Part of #6253

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe): CI configuration

Test plan

  • Unit tests (task test)

  • E2E tests (task test-e2e)

  • Linting (task lint-fix)

  • Manual testing (describe below)

  • Read stacklok/releaseo's action.yml to establish what the token is actually used for, rather than inferring it from the workflow: it is passed as GITHUB_TOKEN to the releaseo binary, which creates the branch and the pull request. Nothing else in this workflow consumes the app token — the stale-branch cleanup step uses secrets.GITHUB_TOKEN.

  • Workflow parses as YAML; actionlint clean.

  • zizmor on this file: github-app 1 → 0, template-injection 3 → 0.

  • Exercised for real via the dispatch described above — token minted, branch pushed, pull request opened, summary rendered. Cleaned up afterwards.

Does this introduce a user-facing change?

No. The app installation holds both permissions, confirmed by the dispatch run.

Special notes for reviewers

  • The artipacked finding on the checkout is left alone on purpose. releaseo takes the token as an explicit input, which strongly suggests it authenticates itself rather than using the credential actions/checkout leaves in .git/config — but "strongly suggests" is not verification, and if it does rely on the persisted credential then persist-credentials: false would break release PR creation. Not worth guessing at in a workflow that cannot be tested by an ordinary pull request.
  • The remaining app tokens (create-release-tag.yml, and the Homebrew tap token in releaser.yml) use the same pattern, so this run de-risks them — but note the Homebrew one is a different app, HOMEBREW_TAP_APP, whose installation permissions are still unverified and which cannot be dispatch-tested.

Generated with Claude Code

actions/create-github-app-token with no permission-* inputs mints a
token carrying every permission the app installation holds. This one is
handed to releaseo, which pushes a branch and opens a pull request, so
contents and pull-requests are all it needs.

Also binds the three releaseo outputs in the summary step through env:
rather than interpolating them into the shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ChrisJBurns
ChrisJBurns requested a review from JAORMX as a code owner August 10, 2026 17:59
@github-actions github-actions Bot added the size/XS Extra small PR: < 100 lines changed label Aug 10, 2026
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.74%. Comparing base (d163115) to head (31778ce).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6266      +/-   ##
==========================================
+ Coverage   72.71%   72.74%   +0.02%     
==========================================
  Files         742      742              
  Lines       77299    77299              
==========================================
+ Hits        56209    56228      +19     
+ Misses      17126    17110      -16     
+ Partials     3964     3961       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ChrisJBurns ChrisJBurns mentioned this pull request Aug 10, 2026
2 tasks
@ChrisJBurns

Copy link
Copy Markdown
Collaborator Author

Validated by dispatch rather than left as an open question — run 31419393149, triggered from this branch with bump_type=patch.

All three steps that mattered passed: the token minted (so RELEASE_APP does hold both permissions), releaseo pushed a branch and opened a pull request using the narrowed token, and the summary step rendered. It created #6267 Release v0.42.2, which is now closed with its branch deleted; main's VERSION is still 0.42.1.

That was the only blocker I had flagged on this PR, so it is ready.

One carry-over for the remaining app-token work: the Homebrew tap token in releaser.yml uses a different app (HOMEBREW_TAP_APP), so its installation permissions are still unverified, and releaser.yml cannot be dispatch-tested.

@github-actions github-actions Bot added size/XS Extra small PR: < 100 lines changed and removed size/XS Extra small PR: < 100 lines changed labels Aug 10, 2026
@ChrisJBurns
ChrisJBurns merged commit ba2cbcb into main Aug 10, 2026
47 checks passed
@ChrisJBurns
ChrisJBurns deleted the harden-release-pr-token branch August 10, 2026 19:08
@github-actions github-actions Bot mentioned this pull request Aug 14, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XS Extra small PR: < 100 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants