-
-
Notifications
You must be signed in to change notification settings - Fork 7
fix: complete script injection hardening across all actions #152
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -77,47 +77,47 @@ runs: | |||||||||||||||||||
| DEPENDENCY_NAME: ${{ inputs.name }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| # Validate that inputs.name contains only safe characters | ||||||||||||||||||||
| if ("$env:DEPENDENCY_NAME" -notmatch '^[a-zA-Z0-9_\./@\s-]+$') { | ||||||||||||||||||||
| Write-Output "::error::Invalid dependency name: '$env:DEPENDENCY_NAME'. Only alphanumeric characters, spaces, and _-./@ are allowed." | ||||||||||||||||||||
| if ($env:DEPENDENCY_NAME -notmatch '^[a-zA-Z0-9_\./@\s-]+$') { | ||||||||||||||||||||
| Write-Output ('::error::Invalid dependency name: "' + $env:DEPENDENCY_NAME + '". Only alphanumeric characters, spaces, and _-./@ are allowed.') | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Write-Output "✓ Dependency name '$env:DEPENDENCY_NAME' is valid" | ||||||||||||||||||||
| Write-Output ('Dependency name "' + $env:DEPENDENCY_NAME + '" is valid') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Validate dependency path | ||||||||||||||||||||
| shell: pwsh | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| DEPENDENCY_PATH: ${{ inputs.path }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| # Validate that inputs.path contains only safe characters (including # for CMake dependencies) | ||||||||||||||||||||
| if ("$env:DEPENDENCY_PATH" -notmatch '^[a-zA-Z0-9_\./#-]+$') { | ||||||||||||||||||||
| Write-Output "::error::Invalid dependency path: '$env:DEPENDENCY_PATH'. Only alphanumeric characters and _-./# are allowed." | ||||||||||||||||||||
| if ($env:DEPENDENCY_PATH -notmatch '^[a-zA-Z0-9_\./#-]+$') { | ||||||||||||||||||||
| Write-Output ('::error::Invalid dependency path: "' + $env:DEPENDENCY_PATH + '". Only alphanumeric characters and _-./# are allowed.') | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Write-Output "✓ Dependency path '$env:DEPENDENCY_PATH' is valid" | ||||||||||||||||||||
| Write-Output ('Dependency path "' + $env:DEPENDENCY_PATH + '" is valid') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Validate changelog-entry | ||||||||||||||||||||
| shell: pwsh | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| CHANGELOG_ENTRY: ${{ inputs.changelog-entry }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| # Validate that inputs.changelog-entry is either 'true' or 'false' | ||||||||||||||||||||
| if ("$env:CHANGELOG_ENTRY" -notin @('true', 'false')) { | ||||||||||||||||||||
| Write-Output "::error::Invalid changelog-entry value: '$env:CHANGELOG_ENTRY'. Only 'true' or 'false' are allowed." | ||||||||||||||||||||
| if ($env:CHANGELOG_ENTRY -notin @('true', 'false')) { | ||||||||||||||||||||
| Write-Output ('::error::Invalid changelog-entry value: "' + $env:CHANGELOG_ENTRY + '". Only "true" or "false" are allowed.') | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Write-Output "✓ Changelog-entry value '$env:CHANGELOG_ENTRY' is valid" | ||||||||||||||||||||
| Write-Output ('Changelog-entry value "' + $env:CHANGELOG_ENTRY + '" is valid') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Validate pr-strategy | ||||||||||||||||||||
| shell: pwsh | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| PR_STRATEGY: ${{ inputs.pr-strategy }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| # Validate that inputs.pr-strategy is either 'create' or 'update' | ||||||||||||||||||||
| if ("$env:PR_STRATEGY" -notin @('create', 'update')) { | ||||||||||||||||||||
| Write-Output "::error::Invalid pr-strategy value: '$env:PR_STRATEGY'. Only 'create' or 'update' are allowed." | ||||||||||||||||||||
| if ($env:PR_STRATEGY -notin @('create', 'update')) { | ||||||||||||||||||||
| Write-Output ('::error::Invalid pr-strategy value: "' + $env:PR_STRATEGY + '". Only "create" or "update" are allowed.') | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Write-Output "✓ PR strategy value '$env:PR_STRATEGY' is valid" | ||||||||||||||||||||
| Write-Output ('PR strategy value "' + $env:PR_STRATEGY + '" is valid') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Validate post-update-script | ||||||||||||||||||||
| if: ${{ inputs.post-update-script != '' }} | ||||||||||||||||||||
|
|
@@ -126,11 +126,11 @@ runs: | |||||||||||||||||||
| POST_UPDATE_SCRIPT: ${{ inputs.post-update-script }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| # Validate that inputs.post-update-script contains only safe characters | ||||||||||||||||||||
| if ("$env:POST_UPDATE_SCRIPT" -notmatch '^[a-zA-Z0-9_\./#\s-]+$') { | ||||||||||||||||||||
| Write-Output "::error::Invalid post-update-script path: '$env:POST_UPDATE_SCRIPT'. Only alphanumeric characters, spaces, and _-./# are allowed." | ||||||||||||||||||||
| if ($env:POST_UPDATE_SCRIPT -notmatch '^[a-zA-Z0-9_\./#\s-]+$') { | ||||||||||||||||||||
| Write-Output ('::error::Invalid post-update-script path: "' + $env:POST_UPDATE_SCRIPT + '". Only alphanumeric characters, spaces, and _-./# are allowed.') | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Write-Output "✓ Post-update script path '$env:POST_UPDATE_SCRIPT' is valid" | ||||||||||||||||||||
| Write-Output ('Post-update script path "' + $env:POST_UPDATE_SCRIPT + '" is valid') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Validate authentication inputs | ||||||||||||||||||||
| shell: pwsh | ||||||||||||||||||||
|
|
@@ -288,30 +288,31 @@ runs: | |||||||||||||||||||
| PR_STRATEGY: ${{ inputs.pr-strategy }} | ||||||||||||||||||||
| DEPENDENCY_PATH: ${{ inputs.path }} | ||||||||||||||||||||
| TARGET_BRANCH: ${{ inputs.target-branch }} | ||||||||||||||||||||
| LATEST_TAG: ${{ steps.target.outputs.latestTag }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| if ([string]::IsNullOrEmpty($env:TARGET_BRANCH)) { | ||||||||||||||||||||
| $mainBranch = $(git remote show origin | Select-String "HEAD branch: (.*)").Matches[0].Groups[1].Value | ||||||||||||||||||||
| $prBranchPrefix = '' | ||||||||||||||||||||
| } else { | ||||||||||||||||||||
| $mainBranch = $env:TARGET_BRANCH | ||||||||||||||||||||
| $prBranchPrefix = "$mainBranch-" | ||||||||||||||||||||
| $prBranchPrefix = $mainBranch + '-' | ||||||||||||||||||||
| } | ||||||||||||||||||||
| $prBranch = switch ($env:PR_STRATEGY) | ||||||||||||||||||||
| { | ||||||||||||||||||||
| 'create' { "deps/$env:DEPENDENCY_PATH/${{ steps.target.outputs.latestTag }}" } | ||||||||||||||||||||
| 'update' { "deps/$env:DEPENDENCY_PATH" } | ||||||||||||||||||||
| default { throw "Unkown PR strategy '$env:PR_STRATEGY'." } | ||||||||||||||||||||
| 'create' { 'deps/' + $env:DEPENDENCY_PATH + '/' + $env:LATEST_TAG } | ||||||||||||||||||||
| 'update' { 'deps/' + $env:DEPENDENCY_PATH } | ||||||||||||||||||||
| default { throw ('Unkown PR strategy "' + $env:PR_STRATEGY + '".') } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| $prBranch = $prBranchPrefix + $prBranch | ||||||||||||||||||||
| "baseBranch=$mainBranch" | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| "prBranch=$prBranch" | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| ('baseBranch=' + $mainBranch) | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| ('prBranch=' + $prBranch) | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| $nonBotCommits = ${{ github.action_path }}/scripts/nonbot-commits.ps1 ` | ||||||||||||||||||||
| -RepoUrl "$(git config --get remote.origin.url)" -PrBranch $prBranch -MainBranch $mainBranch | ||||||||||||||||||||
| -RepoUrl $(git config --get remote.origin.url) -PrBranch $prBranch -MainBranch $mainBranch | ||||||||||||||||||||
| $changed = $nonBotCommits.Length -gt 0 ? 'true' : 'false' | ||||||||||||||||||||
| "changed=$changed" | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| if ("$changed" -eq "true") | ||||||||||||||||||||
| ('changed=' + $changed) | Tee-Object $env:GITHUB_OUTPUT -Append | ||||||||||||||||||||
| if ($changed -eq 'true') | ||||||||||||||||||||
| { | ||||||||||||||||||||
| Write-Output "::warning::Target branch '$prBranch' has been changed manually - skipping updater to avoid overwriting these changes." | ||||||||||||||||||||
| Write-Output ('::warning::Target branch "' + $prBranch + '" has been changed manually - skipping updater to avoid overwriting these changes.') | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Parse the existing PR URL | ||||||||||||||||||||
|
|
@@ -321,19 +322,22 @@ runs: | |||||||||||||||||||
| working-directory: caller-repo | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| GH_TOKEN: ${{ inputs.api-token || github.token }} | ||||||||||||||||||||
| BASE_BRANCH: ${{ steps.root.outputs.baseBranch }} | ||||||||||||||||||||
| PR_BRANCH: ${{ steps.root.outputs.prBranch }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| $urls = @(gh api 'repos/${{ github.repository }}/pulls?base=${{ steps.root.outputs.baseBranch }}&head=${{ github.repository_owner }}:${{ steps.root.outputs.prBranch }}' --jq '.[].html_url') | ||||||||||||||||||||
| $apiUrl = 'repos/${{ github.repository }}/pulls?base=' + $env:BASE_BRANCH + '&head=${{ github.repository_owner }}:' + $env:PR_BRANCH | ||||||||||||||||||||
| $urls = @(gh api $apiUrl --jq '.[].html_url') | ||||||||||||||||||||
|
Comment on lines
+328
to
+329
|
||||||||||||||||||||
| $apiUrl = 'repos/${{ github.repository }}/pulls?base=' + $env:BASE_BRANCH + '&head=${{ github.repository_owner }}:' + $env:PR_BRANCH | |
| $urls = @(gh api $apiUrl --jq '.[].html_url') | |
| $urls = @( | |
| gh api ` | |
| repos/${{ github.repository }}/pulls ` | |
| -f "base=$env:BASE_BRANCH" ` | |
| -f "head=${{ github.repository_owner }}:$env:PR_BRANCH" ` | |
| --jq '.[].html_url' | |
| ) |
Copilot
AI
Mar 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When $urls is an array (the branch where this throw happens), concatenating it into a string will produce an unhelpful value (often "System.Object[]") instead of the matched URLs. Consider joining the array (e.g., with -join) so the exception message contains the actual URLs for debugging.
| throw ('Unexpected number of PRs matched (' + $urls.Length + '): ' + $urls) | |
| throw ('Unexpected number of PRs matched (' + $urls.Length + '): ' + ($urls -join ', ')) |
Uh oh!
There was an error while loading. Please reload this page.