When to Use pull_request_target Instead of pull_request in GitHub Actions

I recently was pulling my hair out trying to debug why my GitHub Actions weren't receiving secrets during one of my Actions executions.

And it turned out I needed to use pull_request_target instead of pull_request.

Choosing the right one is crucial for both functionality and security.

What is pull_request?

The pull_request event is used for day-to-day tasks related to pull requests. These include building, testing, and linting your code whenever someone opens, updates, or reopens a pull request. It's safe and straightforward for use within your repository. It's usually the option you'll choose unless you are writing Actions for external contributors.

What is pull_request_target?

The pull_request_target event is a bit different. It's used when you need to perform more sensitive operations that require access to secrets – like deploying code or accessing private data. This event is more powerful and riskier because it can access more information.

When to Use pull_request_target

You should use pull_request_target in scenarios where:

  1. Access to Secrets is Required: If your workflow needs to use secrets, like deploying code to a server, pull_request_target is the way to go.

  2. Handling Forks Safely: When dealing with pull requests from forks, especially in open-source projects, pull_request_target ensures that your secrets are not exposed to potentially untrusted code.

Situational Example: Using GitHub Secrets

Let's say you have a workflow that deploys your code to a cloud service. You must use a secret API key stored in GitHub Secrets to do this.

  • With pull_request, if someone from outside your team makes a pull request from a fork, your workflow won't have access to this secret API key. It keeps your secrets safe, but you can't auto-deploy from these pull requests.

  • With pull_request_target, you can access this secret API key even in pull requests from forks. This is great for automation, but you need to be extra careful. Make sure you trust the code you're deploying!

Here's the example of where I needed pull_request_target to allow my tests to run with a secret so you can see it in action:

name: Playwright Tests
on:
  push:
    branches: [develop]
  pull_request_target:
    branches: [develop]
    types: [opened, synchronize, reopened, ready_for_review]
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright Browsers
        run: npx playwright install --with-deps
      - name: Run Playwright tests
        env:
          DATABASE_URL: ${{ secrets.DATABASE_URL }}
        run: npx playwright test
      - uses: actions/upload-artifact@v3
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

Be Careful!

Remember, pull_request_target can expose your secrets if not used carefully.

Always review and validate the changes in pull requests before they are merged.

Happy coding! ✨

GITGITHUB
Avatar for Niall Maher

Written by Niall Maher

Founder of Codú - The web developer community! I've worked in nearly every corner of technology businesses; Lead Developer, Software Architect, Product Manager, CTO and now happily a Founder.

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.