diff --git a/.github/workflows/updater.yml b/.github/workflows/updater.yml index 7b70200..d7a1357 100644 --- a/.github/workflows/updater.yml +++ b/.github/workflows/updater.yml @@ -72,6 +72,29 @@ jobs: with: access_token: ${{ github.token }} + validate-inputs: + runs-on: ubuntu-latest + steps: + - name: Validate dependency name + shell: pwsh + run: | + # Validate that inputs.name contains only safe characters + if ('${{ inputs.name }}' -notmatch '^[a-zA-Z0-9_\./@\s-]+$') { + Write-Output "::error::Invalid dependency name: '${{ inputs.name }}'. Only alphanumeric characters, spaces, and _-./@ are allowed." + exit 1 + } + Write-Output "✓ Dependency name '${{ inputs.name }}' is valid" + + - name: Validate dependency path + shell: pwsh + run: | + # Validate that inputs.path contains only safe characters + if ('${{ inputs.path }}' -notmatch '^[a-zA-Z0-9_\./-]+$') { + Write-Output "::error::Invalid dependency path: '${{ inputs.path }}'. Only alphanumeric characters and _-./ are allowed." + exit 1 + } + Write-Output "✓ Dependency path '${{ inputs.path }}' is valid" + # What we need to accomplish: # * update to the latest tag # * create a PR @@ -90,6 +113,7 @@ jobs: # We do different approach on subsequent runs because otherwise we would spam users' mailboxes # with notifications about pushes to existing PRs. This way there is actually no push if not needed. update: + needs: validate-inputs runs-on: ${{ inputs.runs-on }} # Map the job outputs to step outputs outputs: @@ -102,6 +126,12 @@ jobs: defaults: run: shell: pwsh + env: + DEPENDENCY_NAME: ${{ inputs.name }} + DEPENDENCY_PATH: ${{ inputs.path }} + DEPENDENCY_PATTERN: ${{ inputs.pattern }} + CHANGELOG_SECTION: ${{ inputs.changelog-section }} + PR_STRATEGY: ${{ inputs.pr-strategy }} steps: - uses: actions/checkout@v4 with: @@ -121,18 +151,18 @@ jobs: - name: Update to the latest version id: target - run: ${{ runner.temp }}/ghwf/updater/scripts/update-dependency.ps1 -Path '${{ inputs.path }}' -Pattern '${{ inputs.pattern }}' + run: ${{ runner.temp }}/ghwf/updater/scripts/update-dependency.ps1 -Path "$env:DEPENDENCY_PATH" -Pattern "$env:DEPENDENCY_PATTERN" - name: Get the base repo info if: steps.target.outputs.latestTag != steps.target.outputs.originalTag id: root run: | $mainBranch = $(git remote show origin | Select-String "HEAD branch: (.*)").Matches[0].Groups[1].Value - $prBranch = switch ('${{ inputs.pr-strategy }}') + $prBranch = switch ($env:PR_STRATEGY) { - 'create' { 'deps/${{ inputs.path }}/${{ steps.target.outputs.latestTag }}' } - 'update' { 'deps/${{ inputs.path }}' } - default { throw "Unkown PR strategy '${{ inputs.pr-strategy }}'." } + 'create' { "deps/$env:DEPENDENCY_PATH/${{ steps.target.outputs.latestTag }}" } + 'update' { "deps/$env:DEPENDENCY_PATH" } + default { throw "Unkown PR strategy '$env:PR_STRATEGY'." } } "baseBranch=$mainBranch" | Tee-Object $env:GITHUB_OUTPUT -Append "prBranch=$prBranch" | Tee-Object $env:GITHUB_OUTPUT -Append @@ -185,11 +215,11 @@ jobs: with: base: ${{ steps.root.outputs.baseBranch }} branch: ${{ steps.root.outputs.prBranch }} - commit-message: 'chore: update ${{ inputs.path }} to ${{ steps.target.outputs.latestTag }}' + commit-message: 'chore: update ${{ env.DEPENDENCY_PATH }} to ${{ steps.target.outputs.latestTag }}' author: 'GitHub ' - title: 'chore(deps): update ${{ inputs.name }} to ${{ steps.target.outputs.latestTagNice }}' + title: 'chore(deps): update ${{ env.DEPENDENCY_NAME }} to ${{ steps.target.outputs.latestTagNice }}' body: | - Bumps ${{ inputs.path }} from ${{ steps.target.outputs.originalTag }} to ${{ steps.target.outputs.latestTag }}. + Bumps ${{ env.DEPENDENCY_PATH }} from ${{ steps.target.outputs.originalTag }} to ${{ steps.target.outputs.latestTag }}. Auto-generated by a [dependency updater](https://github.com/getsentry/github-workflows/blob/main/.github/workflows/updater.yml). ${{ env.TARGET_CHANGELOG }} @@ -223,19 +253,19 @@ jobs: - name: 'After new PR: redo the update' if: ${{ ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.existing-pr.outputs.url == '') && ( steps.root.outputs.changed == 'false') }} - run: ${{ runner.temp }}/ghwf/updater/scripts/update-dependency.ps1 -Path '${{ inputs.path }}' -Tag '${{ steps.target.outputs.latestTag }}' + run: ${{ runner.temp }}/ghwf/updater/scripts/update-dependency.ps1 -Path "$env:DEPENDENCY_PATH" -Tag '${{ steps.target.outputs.latestTag }}' - name: Update Changelog if: ${{ inputs.changelog-entry && ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.root.outputs.changed == 'false') }} run: | ${{ runner.temp }}/ghwf/updater/scripts/update-changelog.ps1 ` - -Name '${{ inputs.name }}' ` + -Name "$env:DEPENDENCY_NAME" ` -PR '${{ steps.pr.outputs.url }}' ` -RepoUrl '${{ steps.target.outputs.url }}' ` -MainBranch '${{ steps.target.outputs.mainBranch }}' ` -OldTag '${{ steps.target.outputs.originalTag }}' ` -NewTag '${{ steps.target.outputs.latestTag }}' ` - -Section '${{ inputs.changelog-section }}' + -Section "$env:CHANGELOG_SECTION" - run: git --no-pager diff if: ${{ ( steps.target.outputs.latestTag != steps.target.outputs.originalTag ) && ( steps.root.outputs.changed == 'false') }} @@ -247,11 +277,11 @@ jobs: with: base: ${{ steps.root.outputs.baseBranch }} branch: ${{ steps.root.outputs.prBranch }} - commit-message: 'chore: update ${{ inputs.path }} to ${{ steps.target.outputs.latestTag }}' + commit-message: 'chore: update ${{ env.DEPENDENCY_PATH }} to ${{ steps.target.outputs.latestTag }}' author: 'GitHub ' - title: 'chore(deps): update ${{ inputs.name }} to ${{ steps.target.outputs.latestTagNice }}' + title: 'chore(deps): update ${{ env.DEPENDENCY_NAME }} to ${{ steps.target.outputs.latestTagNice }}' body: | - Bumps ${{ inputs.path }} from ${{ steps.target.outputs.originalTag }} to ${{ steps.target.outputs.latestTag }}. + Bumps ${{ env.DEPENDENCY_PATH }} from ${{ steps.target.outputs.originalTag }} to ${{ steps.target.outputs.latestTag }}. Auto-generated by a [dependency updater](https://github.com/getsentry/github-workflows/blob/main/.github/workflows/updater.yml). ${{ env.TARGET_CHANGELOG }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b470d7..83ed5ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Security + +- Updater - Prevent script injection vulnerabilities through workflow inputs ([#98](https://github.com/getsentry/github-workflows/pull/98)) + ## 2.13.1 ### Fixes