All Articles

Running Renovate as a GitHub Action (and NO PAT!)

Adrian Mouat, Staff Developer Relations Engineer

There are two big security measures I wish everyone would adopt: keep dependencies up to date and get rid of all long-lived tokens. This blog covers both at once: how to use Renovate to update your dependencies and how to do so without needing a GitHub Personal Access Token (PAT). We will replace PAT by using Octo STS, an open source tool that was built by and used at scale within Chainguard.

Keeping dependencies up-to-date is essential for both security — running on older versions of software exposes you to vulnerabilities and bugs that are fixed in newer versions. It's also bad for maintenance; it is more work to update across multiple versions than to make small incremental changes over time.

Look at the security reports for incidents, and you will often find a long-lived token of some sort was involved. Many attacks pivot around gaining access to a token and exploiting that to gain further access. The frustrating thing is that in many cases, the long-lived tokens are unnecessary and can be eliminated, nullifying this attack vector.

It makes sense to run tooling such as Dependabot, digestabot, or, as in this article, Renovate on your repositories to automate keeping dependencies up to date. The tools all work in the same broad way: they scan your repository and open a PR to update outdated software versions. The tools are highly configurable, so you can control which files to scan and which updates you're interested in (e.g., apply patch and minor updates but not major updates).

Renovate offers multiple installation options: you can use the Mend-hosted option, self-host, or run it as a GitHub Action. For smaller projects, GitHub Actions is an appropriate approach, requiring little configuration and no additional resources. When run as an Action, the check occurs on a schedule, so it will be slightly slower to pick up updates than the other approaches.

Setting up the GitHub Action

So how do you run Renovate as a GitHub Action? The official docs are great, but the focus is on configuration options rather than installation guides. I'll walk through the steps here, using the prod-container-builds-with-actions repository as a guide.

Most of the work is creating a workflow that runs Renovate on a schedule. The one for the example project looks like this (with a few simplifications):

name: Renovate

on:
  workflow_dispatch:
  schedule:
    - cron: "0 3 * * *"

permissions:
  contents: read

jobs:
  renovate:
    name: Renovate
    runs-on: ubuntu-latest

    permissions:
      id-token: write # required for federation
      contents: write

    steps:
    - uses: octo-sts/action@f603d3be9d8dd9871a265776e625a27b00effe05 # v1.1.1
      id: octo-sts
      with:
        scope: ${{ github.repository }}
        identity: renovate

    - name: Run Renovate
      uses: renovatebot/github-action@822441559e94f98b67b82d97ab89fe3003b0a247 # v44.2.0
      env:
        RENOVATE_TOKEN: ${{ steps.octo-sts.outputs.token }}
        RENOVATE_REPOSITORIES: ${{ github.repository }}

The first part is straightforward; schedule the action to run at 3 in the morning, and also give me a trigger so I can run it manually:

on:
  workflow_dispatch:
  schedule:
    - cron: "0 3 * * *"

And the last part is where we actually run renovate:

    - name: Run Renovate
      uses: renovatebot/github-action@822441559e94f98b67b82d97ab89fe3003b0a247 # v44.2.0
      env:
        RENOVATE_TOKEN: ${{ steps.octo-sts.outputs.token }}
        RENOVATE_REPOSITORIES: ${{ github.repository }}

This runs the Renovate GitHub Action on the current repository. But what's the RENOVATE_TOKEN about? Well, that's where you give Renovate access to the source repository -- in this case, it's the GitHub token. (Mend didn’t call it GITHUB_TOKEN because Renovate works with other CI/CD systems as well). In the official instructions, the advice is to set up fine-grained PAT. But a PAT is a long-lived access token that attackers love to steal. So is there another option? If you're a GitHub Actions aficionado, you might be shouting at the post, "Just use the Action's token!" and you can do this. Sort of. It works, but the token lacks some privileges that can't be conferred via the permissions syntax. The most apparent effect is that Renovate won't be able to update GitHub Actions, which will be a deal-breaker for many teams. But it turns out there is another solution.

Octo STS

Octo STS is a security token service that allows you to trade an OIDC token for a GitHub one. So, for example, you could allow a cloud service in Google access to read a repository. Or, as in this case, we can trade the existing token in the GitHub action for one with greater privileges.

To do this, the first step is to install the Octo STS app. The app requires a superset of privileges, but you can scope which repositories it applies to. The token swap is called from this part of the workflow:

    - uses: octo-sts/action@f603d3be9d8dd9871a265776e625a27b00effe05 # v1.1.1
      id: octo-sts
      with:
        scope: ${{ github.repository }}
        identity: renovate

And there is one last step. When the Octo STS action runs, it calls the Octo STS app with the Action's GitHub token. The app then looks up the repository requested in the scope field and downloads the appropriate .sts.yaml file from the .github/chainguard directory, in this case, .github/chainguard/renovate.sts.yaml. That file looks like this:

issuer: https://token.actions.githubusercontent.com
subject: repo:chainguard-demo/prod-container-builds-with-actions:ref:refs/heads/main

permissions:
  checks: write
  contents: write
  issues: write
  members: read
  pull_requests: write
  statuses: write
  workflows: write

The app will compare the token it's given to the issuer and the subject here. If they match, it will issue a new token with the requested permissions. Renovate then uses that token in the final step to successfully scan the repository.

To get this working on your repo, you will need to create the .github/chainguard/renovate.sts.yaml file and update the subject field to match your repository.

Renovate Configuration and Best Practice

The final file you will want to add is the renovate config. In the example repo, I've put the following renovate.json in the root directory, but renovate supports multiple formats and files:

{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [ 
    "config:best-practices",
    "helpers:pinGitHubActionDigestsToSemver"
  ],
  "minimumReleaseAge": "1 day",
  "prHourlyLimit": 0,
  "automergeType": "pr",
  "packageRules": [
    {
      "description": "Automerge safe updates (patch/minor) plus digest updates once checks pass",
      "matchUpdateTypes": ["patch", "minor", "digest"],
      "automerge": true
    }
  ]
}

This configuration is based on the Renovate best practices documentation. Some of the major points:

  • Both container images and actions will be pinned to digests. Everyone should do this for reproducibility and security.

  • There is a 1-day cool-down (minimumReleaseAge), meaning that only dependencies older than 1 day will be installed. This is intended to mitigate against incidents where malicious versions of packages are published and then quickly pulled (as in the Shai Hulud incidents).

  • Automerge is configured for all but major version updates. This means PRs opened by renovate will be automatically merged. The correct settings here are project-specific, and you may not want this configured at all. For the example repo, I am more concerned with keeping everything up to date than with occasional breakages.

Time for a test run

And that's all the steps. If you've been following along, you should be able to go to the Actions tab in your GitHub project, select the Renovate Action, and click on "Run workflow". With any luck, you will be rewarded with PRs similar to this one:

By default, Renovate will only open a handful of PRs at a time. You can override this, but it's easy to run into merge conflicts that require rebasing, so it's helpful to rate-limit. If you close a PR without merging, renovate will assume you don't want that update and won't reopen the PR (change the name if you need it to open a new PR).

Recap

That was a lot, so as a brief recap, to get Renovate working as a GitHub Action with Octo STS:

Keeping dependencies up to date and eliminating long-lived credentials are two of the simplest, highest-impact security improvements you can make. Running Renovate as a GitHub Action with Octo STS lets you do both at once: automated updates without a permanent token sitting around waiting to be stolen.

Share this article

Related articles

Want to learn more about Chainguard?