Dependabot is a tool for automatic dependency management that was created initially as an external service before being acquired and integrated natively into GitHub. We have been using it extensively since its early versions to automatically upgrade versions of the packages used by our repositories.
We believe that continuous dependency upgrades allow our applications and packages to stay up to date with the latest features, bugs and security fixes by spreading the effort of doing so over a longer period of time. Conversely, delaying package updates postpones the effort to a time when upgrading may be too costly, or even impossible.
We have successfully used dependency automation via services including Greenkeeper (now Snyk) and Renovate, but since Dependabot was integrated natively within GitHub last year we started using it almost exclusively.
At NearForm, we maintain tens of open source npm packages and many other applications we build internally and for our customers. We also contribute to many open source projects, including a large number of repositories in the Fastify ecosystem.
Doing manual maintenance on all of them involves considerable effort, so we looked into ways to automate this process.
Dependabot is configured using a
.github/dependabot.yml file in any repository. This file contains configuration options to choose which package ecosystems to include (e.g.
github-actions ) and a set of configuration options to tune the schedule, ignores and so on. For a list of all configuration options, see the documentation .
A dependabot.yml file may look something like this:
When a dependency is out of date, Dependabot opens a pull request on the repository, which updates the files where the dependency is tracked.
A typical Depandabot PR will look like this:
The advantage of using a tool like Dependabot to automatically attempt to upgrade dependency versions is that by opening a pull request, all the checks in place in the repository will run against the updated versions. For example, these checks could run automated tests against the upgraded dependency, which provides a certain degree of confidence about whether the upgrade is safe or if manual changes are needed.
Most of the repositories we contribute to contain npm packages. Because of their standalone nature they often have very high test coverage, meaning that a green build usually implies that the change made in a PR is safe to integrate into the base branch.
We usually configure the repositories so that a PR cannot be merged until:
When both requirements are satisfied, the PR can be merged and a repository contributor usually does that manually.
GitHub has recently introduced the ability to automatically merge PRs whose requirements are satisfied without human intervention. We have used this feature in some repositories, but we haven’t found it extremely useful in the scope of the automation that we have set up for Dependabot PRs.
Manually reviewing, approving and merging Dependabot PRs over a large number of repositories is a lot of effort, so we looked into ways to automate this.
Our first approach was to use a custom GitHub action that we could include in any workflow. We configured it in this way:
This would trigger the
automerge job after the
build job completed successfully and invoke the custom
fastify/github-action-merge-dependabot action if the run was triggered by a pull request. It would also provide the built-in
GITHUB_TOKEN secret to the action, which could use it to approve and merge the PR.
This approach worked flawlessly until recently, when GitHub introduced restrictions on the permissions of the
GITHUB_TOKEN secret and the visibility of secrets in workflow runs triggered by Dependabot PRs.
From one day to the next, all our automatic approvals and merges were failing because of
GITHUB_TOKEN loss of write permissions on the repositories.
We evaluated both options and deemed them unsuitable for our purposes for similar reasons: Both of them required changes to the rest of our workflows, and we didn’t want the automerge behavior to affect how the workflows should be written.
Another alternative we evaluated was creating a GitHub App and using it to generate a temporary token with write permissions, to be provided to our custom action as a replacement for the now read-only
We tried using tibdex/github-app-token to do this but we faced the second issue in GitHub’s changes around Dependabot PRs: No secrets besides
GITHUB_TOKEN are available.
Therefore, all we are left with is a
GITHUB_TOKEN which has read-only permissions and can’t do what we need — approving and merging the pull request.
With possibly hundreds of builds broken because of the automerge action failing, we were under pressure to find a solution, so we came up with the idea of implementing a GitHub App running on a server. Once installed on a repository or an organisation, the app would get write permissions on the repository and would be allowed to approve and merge pull requests.
The problems to solve were:
This is what we came up with:
This approach eventually worked, and we have put it in place to restore full automation of Dependabot in our repositories. We are sharing it as open source for anybody who wants to use it, leaving the option to self-host the GitHub app.
Using this approach, we are basically working around the security limitations imposed by GitHub around
GITHUB_TOKEN permissions and visibility of secrets in workflow runs. We are basically trading a read-only token for one with write permissions, even though the latter never leaves the GitHub App.
We believe this is an acceptable compromise between functionality and security because:
Therefore, we believe that the surface of attack and the possible damage are so limited that the risk of a Dependabot PR being unintentionally merged is acceptably low.