Wade
Wade

Reputation: 323

How to push to protected main branches in a GitHub Action?

This is my github action workflow.

name: Release

on:
  push:
    branches:
      - main

jobs:
  release:
    name: Release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false
      - name: Setup java
        uses: actions/setup-java@v1
        with:
          java-version: 11
      - name: Setup node
        uses: actions/setup-node@v1
        with:
          node-version: "14.x"
          cache: npm
      - name: Install dependencies
        run: npm ci
      - name: Build package
        run: npm run build --if-present
      - name: Semantic release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          HUSKY: 0
        run: chmod +x script/prepare-release.sh && npx semantic-release

However, my workflow fails with the following error log.

[semantic-release] › ✖  An error occurred while running semantic-release: Error: Command failed with exit code 1: git push --tags https://x-access-token:[secure]@github.com/didrlgus/convention-template.git HEAD:main
remote: error: GH006: Protected branch update failed for refs/heads/main.        
remote: error: At least 1 approving review is required by reviewers with write access.      

Maybe it's because my main branch is a protected branch.
How can I push with a protected branch on github action?

Upvotes: 31

Views: 19837

Answers (5)

Adrian Molina
Adrian Molina

Reputation: 89

Github App

I would say the best option is creating a Github App

Pros against actual users and deployment keys

  • Granular permissions
  • Can be single or multi repo

Steps to make it work

  1. Create a new Github App under developer settings

  2. Generate private key

    • Once the app was created scroll down and click Generate a private key
    • Save your Private Key (will be used in last the step)
  3. Set Permissions

    • Navigate to Permissions & events on the left menu
    • For push permissions select Repository permissions > Contents > Read and write
  4. Install the app

    • Navigate to Install App on the left menu
    • Install the app and select the repos it can modify
  5. Allow the app bypass the PR restriction

    • Navigate to your repo rule set and add your app to the bypass list
  6. Git action with app credentials

      - uses: actions/create-github-app-token@v1
        id: app-token
        with:
          app-id: ${{ vars.APP_ID }}
          private-key: ${{ secrets.APP_PRIVATE_KEY }}

      - name: Checkout
        uses: actions/checkout@v4
        with:
          token: ${{ steps.app-token.outputs.token }}

      - name: Set User
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

      - name: Push version and tag
        run: | 
          npm version ${{ github.event.inputs.version }}
          git push

Upvotes: 1

YaaZ
YaaZ

Reputation: 490

Just found that you can use GitHub deploy keys:

  1. Generate SSH key pair: ssh-keygen -t ed25519. No need for passphrases etc.

  2. Add public key (.pub one) as a deploy key at Your repo -> Settings -> Security -> Deploy keys, check "Allow write access".

  3. Add private key as a secret at Your repo -> Settings -> Security -> Secrets and variables -> Actions

  4. Specify your secret key when checking out the repo:

    - name: Checkout
      uses: actions/[email protected]
      with:
        ssh-key: ${{secrets.YOUR_SECRET_KEY}}
    

Such deployment key is not tied to any account, but gives full write access including bypassing branch protection rules:

Deploy keys with write access can perform the same actions as an organization member with admin access, or a collaborator on a personal repository.

Upvotes: 17

ChrisAckerman
ChrisAckerman

Reputation: 1

I couldn’t find a solution that was acceptable to me/work. So, the only option I was left with was avoiding updates in CI that need to be pushed up. That means versioning and changelogs have to be done as part of a user commit/PR. And I created some tooling it make sure it’s done right, in case it helps anyone else: https://github.com/Shakeskeyboarde/anglerci

Upvotes: 0

Toomy
Toomy

Reputation: 434

The solution that works for us is as follows:

name: Version and Package Repo
on:
  push:
    branches: [ master, main ]
jobs:
  build:
    if: github.event.commits[0].author.name != 'GitHubActions'
    runs-on: ubuntu-18.04
    steps:
    - name: Checkout repo
      uses: actions/checkout@v2
      with:
        fetch-depth: 0
        token: ${{ secrets.PAT }}
    - name: Configure git
      run: |
        git config user.name "GitHubActions"
        git config user.email "<>"
    - name: Install NPM Packages
      run: npm install
      env:
        NODE_AUTH_TOKEN: $\{{ secrets.PAT }}
    - name: Version and Package
      run: npm version patch --force
      env:
        NODE_AUTH_TOKEN: $\{{ secrets.PAT }}
    - name: Update git
      run: |
        git push
        git push --tags

This runs on all pushes to master and main branches (we use the same script on multiple repos) and it:

  • checks the repo out
  • configures git
  • installs and then versions some NPM packages (not relevant to this issue, aside from the job making some kind of change to the repo) - this creates a new commit
  • pushes the changes back to the same branch

secrets.PAT is a personal access token of a user with admin rights and the repo has branch protection on, but excludes admins.

It is worth considering that if you run git push from an action with the on push trigger and you're using a PAT rather than GITHUB_TOKEN, then the action will run in a loop. If you are using GITHUB_TOKEN then GitHub Actions prevents the action running again automatically. We use the conditional if line at the top of the job to prevent the job running if the author name of the last commit is GitHubActions. This is the author name set in the Configure git stage, so the commits that happen within this job (as a result of npm version patch) are from an author with this name.

If the author variable doesn't work for you, there are plenty of others you can use:

https://docs.github.com/en/actions/learn-github-actions/contexts#github-context https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push

The downside of this approach is that you always get a second run appear in your list of actions which is immediately skipped.

Upvotes: 3

Qwal
Qwal

Reputation: 659

There is a workaround. Steps as follows:

  1. Create new Github user eg. my-org-bot

  2. Generate Personal Access Token for this user on https://github.com/settings/tokens and save it somewhere (select repo scope for the token)

  3. Go to your repo and add my-org-bot to contributors

  4. Open your branch protection rules and add my-org-bot to the rule below: enter image description here

  5. Go to repository secrets and add new secret for Actions with key =BOT_ACCESS_TOKEN and the value = Personal Access Token generated previously

  6. Modify your GH Workflow Checkout step with below: enter image description here

Now your workflow should be able to push directly to your protected branch on behalf of my-org-bot user.

Upvotes: 33

Related Questions