Skip to content

ci(release): keep the publish job's write token out of its checkout and environment - #14306

Open
MarcZX10 wants to merge 2 commits into
boykopovar:mainfrom
MarcZX10:ci/release-publish-scope-token
Open

MarcZX10 wants to merge 2 commits into
boykopovar:mainfrom
MarcZX10:ci/release-publish-scope-token

Conversation

@MarcZX10

@MarcZX10 MarcZX10 commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

What

The publish job in release.yml gives every step GH_TOKEN: ${{ github.token }} with contents: write, and its actions/checkout keeps its credentials on disk. So the tagged repository code that the job runs (tools/package_release.py, tools/prepare_release_notes.py) runs with a write token in its environment and in .git/config. Neither tool needs the token; I checked both and neither calls gh or reads a token variable.

Fix, in two commits:

  • b537e2400e: the checkout sets persist-credentials: false, and GH_TOKEN is set only on the three steps that call gh (release notes, draft and upload, publish). The job-level environment keeps GH_REPO.
  • c0ab0ee272: tools/tests/test_release_workflow.py checks both points, registered in CMakeLists.txt.

Impact is low: only a user who can push a v* tag runs the job, and that user can already release. The change limits what the tagged code can do with the token.

Tested

Linux, Python 3.11.2, on upstream/main c674f8c14d plus these commits:

Not run: a tag-triggered release run. The first release after merge shows whether the three gh steps still have the token they need.

Checklist

  • Based on current main
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 14906 .github/workflows/release.yml L156-157

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 1835 CMakeLists.txt
PR 5021 CMakeLists.txt
PR 7642 CMakeLists.txt
PR 9539 CMakeLists.txt
PR 10193 CMakeLists.txt
PR 13578 CMakeLists.txt
PR 13928 CMakeLists.txt
PR 13929 CMakeLists.txt
PR 14212 CMakeLists.txt
PR 14264 CMakeLists.txt

@maskym

maskym commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

Windows result for head c0ab0ee272, merged alone into main f2d874c1fd (the PR's Tested section names no Windows run).

Host: Windows 11 26300, Python 3.13.5.

python -m unittest tools.tests.test_release_workflow: OK, three runs. Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blocking findings

The release publish job no longer exposes the write token at job level or to the checkout. GH_TOKEN moves to the three steps that call gh, and the checkout keeps no credentials. I checked each gh call and each git command in the job, and none is left without the token or needs the checkout's credentials. The hosted ubuntu CTest run passed release_workflow. The release workflow does not run on pull requests, so its behaviour on a real release is not exercised here.

What I ran

  • Head c0ab0ee272fb4ecc7c24aea3f036dfd921fc1d56; base c2ba690bfc6597c3b33084057a02ffa7f0f49d10. 4 files: .github/workflows/release.yml (the publish job: job env loses GH_TOKEN; the checkout gets persist-credentials: false; GH_TOKEN moves to the release-notes, draft-and-upload and publish steps), CMakeLists.txt (+2: registers release_workflow), and tools/tests/test_release_workflow.py (new, 23 lines: two tests on the publish job's text).
  • Read the publish job from publish: to the end. The gh calls are: gh api ... generate-notes (the release-notes step, with GH_TOKEN in its own env), and gh release list, create, view, edit and upload in the draft-and-upload step (which has GH_TOKEN). The last one is gh release edit --draft=false (the publish step, with GH_TOKEN). No git push, fetch, pull, tag or remote command is in the job.
  • Hosted: the ubuntu relinker job's CTest run for this head (550 of 550 passed) ran release_workflow (Test #36, passed, 0.06 s).
  • Read-only checks from the trusted main checkout: diff check, conventions and PR template, and the stack check all passed. The ABI audit is not applicable. The Python test was not run here, because the PR changes .py files.
  • No MarcZX10 review at this head.

Results

Check Result Note
Diff check passed
Conventions and PR template passed conventions check from the main checkout
Mergeability and dependencies passed stack check passed; no declared dependencies
Every gh call in the publish job has GH_TOKEN passed by reading the draft-and-upload step's env covers its gh release view and the rest of the step
No git command in the publish job needs the checkout's credentials passed by reading none found
release_workflow (hosted, ubuntu CTest) passed Test #36, 0.06 s
The release workflow on a real release not run the release workflow does not run on pull requests
ABI audit not applicable no export changed
Build and runtime tests (Linux) run hosted see above
Negative controls not run no local build
Hosted CI passed conventions, eligibility, intake, labels, relinkers, relinker-asan, windows succeeded; linux skipped
Read-only check output

Precheck was not run: no PR-head code is run here, and the PR changes .py files. Diff check: passed. Conventions: passed. ABI audit: not applicable. Stack check: passed. Hosted: gh api repos/boykopovar/AnyPS5/commits/c0ab0ee272fb4ecc7c24aea3f036dfd921fc1d56/check-runs, and the ubuntu relinker job log.

Negative control

Not run here. A negative control needs a local run of the Python tests and a release run, and neither is available from this head.

Findings

Blocking

None.

Non-blocking

None.

Sources

Not verified

  • A real release run of the publish job with the token moved (the release workflow does not run on pull requests).

To get this to a good state

  • Nothing to change. The first real release after this lands will show whether the moved token works end to end.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 2, 2026
…nd environment

The publish job gave every step GH_TOKEN with contents: write, and its checkout kept its credentials on disk, so tagged repository code ran with a write token in its environment and in .git/config. The checkout no longer persists credentials, and the token is set only on the three steps that call gh.
… of checkout and environment

The tests check that the publish job's checkout sets persist-credentials: false and that GH_TOKEN is not set in the job environment. Against the previous workflow both fail.
@MarcZX10
MarcZX10 force-pushed the ci/release-publish-scope-token branch from c0ab0ee to e2857fc Compare November 4, 2026 11:37
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 4, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants