Stage 2a of the TokenPermissionsID cleanup. Moves `actions: write` from top-level to the `cleanup` job's permissions block, leaving the workflow-level default at `contents: read`.
Why
Per Scorecard alert #528: `score is 0: topLevel 'actions' permission set to 'write'`. Top-level write permissions widen the blast radius — any future job added to this workflow inherits write by default. Pushing the privilege to the job that actually uses it follows least-privilege.
Behavior change
None. The `cleanup` job is the only job in the workflow, and it still gets the same effective permissions (`actions: write` + `contents: read`). The only difference is that the top-level default is now narrower for any future job.
Linked alert
Closes Scorecard #528 (TokenPermissionsID).
SOC2
CC7.1 vulnerability management — least-privilege on workflow tokens; closes one of the deferred Stage 2 alerts after Stage 1 (PR #790) verified the broader pattern.
Stage 2a of the TokenPermissionsID cleanup. Moves `actions: write` from top-level to the `cleanup` job's permissions block, leaving the workflow-level default at `contents: read`.
Why
Per Scorecard alert #528: `score is 0: topLevel 'actions' permission set to 'write'`. Top-level write permissions widen the blast radius — any future job added to this workflow inherits write by default. Pushing the privilege to the job that actually uses it follows least-privilege.
Behavior change
None. The `cleanup` job is the only job in the workflow, and it still gets the same effective permissions (`actions: write` + `contents: read`). The only difference is that the top-level default is now narrower for any future job.
Linked alert
Closes Scorecard #528 (TokenPermissionsID).
SOC2
CC7.1 vulnerability management — least-privilege on workflow tokens; closes one of the deferred Stage 2 alerts after Stage 1 (PR #790) verified the broader pattern.