[release/v7.6.1] [StepSecurity] ci: Harden GitHub Actions tokens#27218
Conversation
Signed-off-by: StepSecurity Bot <bot@stepsecurity.io>
There was a problem hiding this comment.
Pull request overview
Backport to release/v7.6.1 to harden GitHub Actions GITHUB_TOKEN permissions to least-privilege defaults across selected workflows.
Changes:
- Add workflow-level
permissions: contents: readto reusable xUnit test workflow. - Add workflow-level
permissions: contents: readto reusable Windows packaging workflow. - Add
copilot-setup-stepsworkflow withcontents: readpermissions and bootstrapping steps.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| # You can define any steps you want, and they will run before the agent starts. | ||
| # If you do not check out your code, Copilot will do this for you. | ||
| steps: | ||
| - uses: actions/checkout@v6 |
There was a problem hiding this comment.
actions/checkout@v6 is the only usage of checkout v6 in this repo; other workflows use v4/v5 or pin to a specific commit SHA. Please align this workflow to an existing supported version (or a pinned SHA) to avoid failures if v6 is not available and to keep dependencies consistent across workflows.
| - uses: actions/checkout@v6 | |
| - uses: actions/checkout@v5 |
| Import-Module ./build.psm1 -Verbose -ErrorAction Stop | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Switch to public feed' | ||
| Write-LogGroupStart -Title $title | ||
| Switch-PSNugetConfig -Source Public | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Bootstrap' | ||
| Write-LogGroupStart -Title $title | ||
| Start-PSBootstrap -Scenario DotNet | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Install .NET Tools' | ||
| Write-LogGroupStart -Title $title | ||
| Start-PSBootstrap -Scenario Tools | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Sync Tags' | ||
| Write-LogGroupStart -Title $title | ||
| Sync-PSTags -AddRemoteIfMissing | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Setup .NET environment variables' | ||
| Write-LogGroupStart -Title $title | ||
| Find-DotNet -SetDotnetRoot | ||
| Write-LogGroupEnd -Title $title |
There was a problem hiding this comment.
The log group started with Write-Host "::group::$title" isn't guaranteed to be closed if Import-Module fails (the ::endgroup:: is emitted after the failing command). Wrap the grouped block in try/finally so the ::endgroup:: (or equivalent) is always emitted even on errors.
| Import-Module ./build.psm1 -Verbose -ErrorAction Stop | |
| Write-LogGroupEnd -Title $title | |
| $title = 'Switch to public feed' | |
| Write-LogGroupStart -Title $title | |
| Switch-PSNugetConfig -Source Public | |
| Write-LogGroupEnd -Title $title | |
| $title = 'Bootstrap' | |
| Write-LogGroupStart -Title $title | |
| Start-PSBootstrap -Scenario DotNet | |
| Write-LogGroupEnd -Title $title | |
| $title = 'Install .NET Tools' | |
| Write-LogGroupStart -Title $title | |
| Start-PSBootstrap -Scenario Tools | |
| Write-LogGroupEnd -Title $title | |
| $title = 'Sync Tags' | |
| Write-LogGroupStart -Title $title | |
| Sync-PSTags -AddRemoteIfMissing | |
| Write-LogGroupEnd -Title $title | |
| $title = 'Setup .NET environment variables' | |
| Write-LogGroupStart -Title $title | |
| Find-DotNet -SetDotnetRoot | |
| Write-LogGroupEnd -Title $title | |
| try { | |
| Import-Module ./build.psm1 -Verbose -ErrorAction Stop | |
| } | |
| finally { | |
| Write-Host "::endgroup::" | |
| } | |
| $title = 'Switch to public feed' | |
| Write-LogGroupStart -Title $title | |
| try { | |
| Switch-PSNugetConfig -Source Public | |
| } | |
| finally { | |
| Write-LogGroupEnd -Title $title | |
| } | |
| $title = 'Bootstrap' | |
| Write-LogGroupStart -Title $title | |
| try { | |
| Start-PSBootstrap -Scenario DotNet | |
| } | |
| finally { | |
| Write-LogGroupEnd -Title $title | |
| } | |
| $title = 'Install .NET Tools' | |
| Write-LogGroupStart -Title $title | |
| try { | |
| Start-PSBootstrap -Scenario Tools | |
| } | |
| finally { | |
| Write-LogGroupEnd -Title $title | |
| } | |
| $title = 'Sync Tags' | |
| Write-LogGroupStart -Title $title | |
| try { | |
| Sync-PSTags -AddRemoteIfMissing | |
| } | |
| finally { | |
| Write-LogGroupEnd -Title $title | |
| } | |
| $title = 'Setup .NET environment variables' | |
| Write-LogGroupStart -Title $title | |
| try { | |
| Find-DotNet -SetDotnetRoot | |
| } | |
| finally { | |
| Write-LogGroupEnd -Title $title | |
| } |
| Write-Host "::group::$title" | ||
| Import-Module ./build.psm1 -Verbose -ErrorAction Stop | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Switch to public feed' | ||
| Write-LogGroupStart -Title $title | ||
| Switch-PSNugetConfig -Source Public | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Bootstrap' | ||
| Write-LogGroupStart -Title $title | ||
| Start-PSBootstrap -Scenario DotNet | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Install .NET Tools' | ||
| Write-LogGroupStart -Title $title | ||
| Start-PSBootstrap -Scenario Tools | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Sync Tags' | ||
| Write-LogGroupStart -Title $title | ||
| Sync-PSTags -AddRemoteIfMissing | ||
| Write-LogGroupEnd -Title $title | ||
|
|
||
| $title = 'Setup .NET environment variables' | ||
| Write-LogGroupStart -Title $title | ||
| Find-DotNet -SetDotnetRoot | ||
| Write-LogGroupEnd -Title $title |
There was a problem hiding this comment.
Each Write-LogGroupStart should be paired with a guaranteed Write-LogGroupEnd even when a command inside the group throws (e.g., Switch-PSNugetConfig, Start-PSBootstrap). Consider wrapping each grouped section in try/finally so a failure doesn't leave the remainder of the job output collapsed inside an unclosed group.

Backport of #27202 to release/v7.6.1
Triggered by @daxian-dbw on behalf of @step-security-bot
Original CL Label: CL-BuildPackaging
/cc @PowerShell/powershell-maintainers
Impact
REQUIRED: Choose either Tooling Impact or Customer Impact (or both). At least one checkbox must be selected.
Tooling Impact
Backports the GitHub Actions token permission hardening needed to apply least-privilege defaults to release workflow definitions.
Customer Impact
Regression
REQUIRED: Check exactly one box.
This is not a regression.
Testing
Verified by cherry-picking onto release/v7.6.1 and resolving a single delete-vs-add conflict in .github/workflows/copilot-setup-steps.yml by keeping the incoming workflow file from the PR. No local workflow run was performed; CI on the backport PR will validate the updated workflow permissions.
Risk
REQUIRED: Check exactly one box.
Medium risk because the change affects CI workflow permissions, which can break automation if permissions are too restrictive. The scope is limited to workflow metadata and the conflict resolution preserved the incoming security hardening change.
Merge Conflicts
Conflict in .github/workflows/copilot-setup-steps.yml. On release/v7.6.1 the file was absent, while the incoming PR modified it to add workflow-level permissions. Resolved as a delete-vs-add conflict by keeping the incoming workflow file so the token hardening change is preserved.