How to get base SHA when using `pull_request_target`?

Is there a good way to get the merge base when using pull_request_target? With pull_request_target, github.event.pull_request.base.ref changes to be the main branch where the workflow is run from.

I’m using actions/checkout to checkout the ref: github.event.pull_request.head.ref and then tried to git fetch origin master and git merge-base origin/master ${{ github.event.pull_request.head.ref }}, but it always exits with error code.

You need to specify the repo the ref belongs to:

    - name: Checkout
      uses: actions/checkout@v2
      with:
        ref: ${{github.event.pull_request.head.ref}}
        repository: ${{github.event.pull_request.head.repo.full_name}}

I use such configuration for checkout action

- uses: actions/checkout@v2.3.4
  with:
    ref: 'refs/pull/${{ github.event.number }}/merge'

After it I have the same code as for standard pull_request event.

@billyvg,

With pull_request_target, github.event.pull_request.base.ref changes to be the main branch where the workflow is run from.

I do not think the value of “github.event.pull_request.base.ref” will be changed when using the pull_request_target event.

The pull_request_target event is similar to pull_request, except that it runs in the context of the base repository of the pull request, rather than in the merge commit.

The pull_request_target and pull_request run on different Git refs (github.ref) does not mean the head ref (github.head_ref) and the base ref (github.base_ref) also will be different.

Generally, after opening a pull request and selecting the head branch (source branch) and base branch (target branch), the head ref and base ref are fixed and will not automatically changed.

To get the branch names of the head ref and base ref, you can use “github.head_ref” and “github.base_ref”. They are same as “github.event.pull_request.head.ref” and “github.event.pull_request.base.ref”.

In addition, I notice that you are using master in the git commands,

git fetch origin master
git merge-base origin/master ${{ github.event.pull_request.head.ref }}

but in above comment, you mentioned the base ref is main branch. Make sure you are using the correct branch name.

Ah shoot, I must have been tired when I wrote this - what I actually need is the merge base SHA. With pull_request_target, the base SHA always points towards the latest SHA of the merge base ref (e.g. master).

I’m looking for a way to get b in the following example:

a ---b------> d
      \--c

@billyvg,

With pull_request_target, the base SHA always points towards the latest SHA of the merge base ref (e.g. master).

Generally, when opening a PR, the base commit SHA (github.event.pull_request.base.sha) generally will point to the latest commit on the target branch of the PR, if the head branch is up-to-date with the base branch. The base commit SHA normally is fixed and not automatically changed.

During the PR opening, if you push some new commits on the base branch but do not update the PR branch, the head branch and PR branch will be out-of-date with the base branch, and the base commit SHA of the PR will still point to the original commit not the latest one on the base branch.

More details, you can reference to this topic:


In your case, due to you check out the whole base branch, the HEAD will point to the latest commit on the bash branch in the local repository.

git fetch origin master

You can try to only fetch the single base commit SHA via the checkout action in the workflow.
For example:

- name: Checkout
  uses: actions/checkout@v2
  with:
    ref: ${{ github.event.pull_request.base.sha }}

Or use the git checkout command to switch to the base commit SHA.

git checkout ${{ github.event.pull_request.base.sha }}

Thanks @brightran, what I’m doing for now is checkout out with fetch-depth: 0 and using git merge-base

1 Like

@billyvg could you explain what that does? I am trying to do the same, but checking out the head.ref when calling checkout:

- uses: actions/checkout@v2
      with:
        ref: ${{github.event.pull_request.head.ref}}
        repository: ${{github.event.pull_request.head.repo.full_name}} 

But when I do this, I get a security vulnerability in my public repo, so I had to remove this. I got a message from Github that this trigger type is mainly used to commonet on PRs, label them, and assign to people, etc. Without it, the checkout will only ever checkout the base head, which does not contain the contents of the forked repo’s PR. They said that we may be able to use workflow_run to achieve what I am trying to do, but did not go into details about how

Yeah unfortunately this is a security liability, we’re going to refactor to use workflow_run

After speaking to the security team for github actions, they said my use case is not supported. Essentially, if you check out the forked repo’s PR, the forked repo PR could’ve added a pre/post hook script and that could easily be executed if the workflow has a step that executes ‘npm run some-script’.

The forked PR could have a pre-hook script called presome-script that could use the github secrets however they’d like. This should be called out on the documentation as a security vulnerability of this trigger type.

1 Like

More details on secure usage of pull_request_target are available here https://securitylab.github.com/research/github-actions-preventing-pwn-requests

1 Like