🤖

Dependabot for private packages

At Multiverse, I work on our design system and related tooling.

One common issue I’ve come across is keeping our dependencies up to date.

Relying solely on manual updates from teams working in very different areas of the business can be time-consuming and error-prone. And, understandably, projects can find themselves falling behind on updates, especially when updates are coming in thick and fast!

Enter Dependabot

Dependabot is a great tool for keeping dependencies up to date. It works by opening Pull Requests when new versions of your dependencies are released. The frequency of these PRs can be configured to suit your needs.

Companies like Github, Shopify, and Gitlab use Dependabot to keep their dependencies up to date and secure. Urgent security patches are flagged immediately by Dependabot.

Although Dependabot is awesome, it has a big limitation: By default, it will only work with public packages.

To make full use of it’s capabilities, I need it to be able to work with private packages, hosted in Github’s Package Registry.

Setting up the config

Dependabot is configured using a .dependabot/config.yml file in your repository. Here, you specify all sorts of options, like the package ecosystem, frequency of updates, and the branches to monitor.

Here’s a basic example config:

version: 2

updates:
- package-ecosystem: npm
  open-pull-requests-limit: 3
  schedule:
    interval: daily

The above should be pretty self explanatory, but this config will check for updates to npm packages daily and open a maximum of 3 PRs at a time.

Simple!

Adding private packages

We need to tell Dependabot how to access our private packages. This is done by adding a registries section to the config.

registries:
  github-packages:
    type: npm-registry
    url: https://npm.pkg.github.com
    token: ${{secrets.DEPENDABOT_GITHUB_PACKAGES_TOKEN}}

And reference that registry in the updates section:

updates:
- package-ecosystem: npm
  registries:
    - 'github-packages'
  # ...other options

The token is a Github Personal Access Token with the read:packages scope. This token should be stored as a secret in your repository in the “dependabot” section: https://github.com/ORG/REPO/settings/secrets/dependabot

Complete config example

version: 2

updates:
- package-ecosystem: npm
  open-pull-requests-limit: 3
  schedule:
    interval: daily
  registries:
    - 'github-packages'

registries:
  github-packages:
    type: npm-registry
    url: https://npm.pkg.github.com
    token: ${{secrets.DEPENDABOT_GITHUB_PACKAGES_TOKEN}}

Existing yarn & npm configs

You probably already have a .npmrc or .yarnrc.yml file in your repository to authenticate with Github Packages. You can use the same token for Dependabot.

However there is one caveat: Dependabot does not understand environment variables in either of these files.

# .yarnrc.yml
npmScopes:
  c-sinclair:
    npmAlwaysAuth: true
    npmAuthToken: ${GITHUB_PACKAGES_TOKEN}
    npmRegistryServer: 'https://npm.pkg.github.com'
    npmPublishRegistry: 'https://npm.pkg.github.com'

The above will cause Dependabot to fail with an error, so you’ll need to omit the npmAuthToken line from the file.

My solution was to use .yarnrc.yml and .npmrc which live in my home ~ directory, so my local machine can fetch private packages, which dependents relies on its own ${{secrets. }} token provided by Github.

The in CI, I have a line before the yarn install to copy the .yarnrc.yml file to the root of the CI container.

# .github/workflows/ci.yml
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      GITHUB_READ_PACKAGES_TOKEN: ${{secrets.GITHUB_TOKEN}}
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Add Github token to yarn and npm config
        run: |
          echo "//npm.pkg.github.com/:_authToken=${GITHUB_READ_PACKAGES_TOKEN}" > ~/.npmrc
          echo "npmScopes:
            c-sinclair:
              npmAlwaysAuth: true
              npmAuthToken: ${GITHUB_READ_PACKAGES_TOKEN}
              npmRegistryServer: 'https://npm.pkg.github.com\'
            " > ~/.yarnrc.yml

      - name: Install dependencies
        run: yarn install

Conclusion

I hope this guide is an aid to you when setting up Dependabot for your private packages. So far I only have positive feedback from my team, and let’s just say we’re all a lot more up to date with our dependencies now!