Skip to content

Instantly share code, notes, and snippets.

@fxmarty
Last active August 2, 2023 10:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fxmarty/fba1ea3b2ebbf9a75cca71c08f05a85b to your computer and use it in GitHub Desktop.
Save fxmarty/fba1ea3b2ebbf9a75cca71c08f05a85b to your computer and use it in GitHub Desktop.
Safe pull_request_target

We implement https://iterative.ai/blog/testing-external-contributions-using-github-actions-secrets to allow to run workflows that require GitHub secrets on external PRs. For that, one member of the external group needs to approve the workflow.

The authorize job should be required for all following jobs (needs: authorize).

When using actions/checkout, we would like to check out on the merge commit, as this is the default for the pull_request event (but not of the pull_request_target, refer to actions/checkout#518). However, this is in itself not safe as malicious code can be commited between the approval and checkout.

Thus the step

      - name: Security - check PR SHA
        if: github.event_name == 'pull_request_target'
        run: |
            [[ "$(git rev-parse 'HEAD^2')" == "${{ github.event.pull_request.head.sha }}" ]]

is required, checking that the second parent (namely the last PR commit) SHA matches with the SHA captured at the start of the workflow.

All in all this is safe:

name: Unit and integration tests

on:
  workflow_dispatch:
  pull_request_target:

jobs:
  authorize:
    environment:
      ${{ github.event_name == 'pull_request_target' &&
      github.event.pull_request.head.repo.full_name != github.repository &&
      'external' || 'internal' }}
    runs-on: ubuntu-latest
    steps:
      - run: true
  mytest:
    name: Run my tests
    needs: authorize
    steps:
      - name: Checkout on branch
        if: github.event_name != 'pull_request_target'
        uses: actions/checkout@v2
        with:
          ref: ${{ github.ref }}
      - name: Checkout on PR merge commit
        if: github.event_name == 'pull_request_target'
        uses: actions/checkout@v2
        with:
          ref: "refs/pull/${{ github.event.number }}/merge"
          fetch-depth: 2
      - name: Security - check PR SHA
        if: github.event_name == 'pull_request_target'
        run: |
            [[ "$(git rev-parse 'HEAD^2')" == "${{ github.event.pull_request.head.sha }}" ]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment