For the complete documentation index, see llms.txt.

Using Dependabot with Chainguard Containers

How to configure Dependabot to authenticate to your private cgr.dev registry and open pull requests that update Chainguard Containers
  7 min read

Dependabot is GitHub’s dependency update tool. It reads the container image references in your Dockerfiles and Kubernetes manifests, checks the registry for newer tags, and opens pull requests to update them.

This guide explains how to configure Dependabot to authenticate to your organization’s private registry at cgr.dev so it can keep your references to Chainguard Containers current.

Choosing between Dependabot and Digestabot

Dependabot and Digestabot solve different halves of the same problem, and many teams run both:

  • Dependabot opens a pull request when a newer tag is available — for example, moving a reference from go:1.22 to go:1.26. Use it to move between version streams.
  • Digestabot opens a pull request when the digest behind a fixed tag changes. Chainguard rebuilds container images daily, so the digest behind a tag such as latest or 3.14 changes often. Use Digestabot to pick up those rebuilds.

Dependabot acts on the tag string in your reference. If you pin to a mutable tag and never change that string, Dependabot has nothing to update, and Digestabot is the better fit.

Prerequisites

To follow this guide, you need:

  • A GitHub repository containing at least one reference to a Chainguard container image.
  • Access to a Chainguard organization, with permission to create pull tokens.
  • chainctl installed on your local machine. Refer to How to install chainctl if you haven’t set this up.

Create a pull token

Dependabot authenticates to private container registries with a static username and password. It doesn’t support Chainguard assumable identities, so you need to create a pull token.

Create one with chainctl:

chainctl auth configure-docker --pull-token --ttl 2160h

This command responds with output such as the following:

To use this pull token in another environment, run this command:

    docker login "cgr.dev" --username "<USERNAME>" --password "<PASSWORD>"

The username has the form <organization ID>/<pull token ID>. Record both values; you’ll store them as secrets in the next section.

The --ttl flag sets how long the token stays valid. The example uses 2160h, or 90 days. The default is 720h (30 days) and the maximum is 8760h (one year). Dependabot’s authentication fails once the token expires, so choose a lifetime you can commit to rotating, and set a reminder to replace the token before it lapses.

One pull token can serve every repository in your GitHub organization. Storing it as an organization-level secret, rather than creating a token for each repository, leaves you with a single credential to rotate.

Store the credentials as Dependabot secrets

GitHub keeps Dependabot secrets in a separate store from Actions secrets. A token added to Actions secrets is invisible to Dependabot, and the update job fails to authenticate without a clear explanation.

To add the secrets to a single repository:

  1. In your repository on GitHub, go to Settings > Secrets and variables > Dependabot.
  2. Select New repository secret.
  3. Name the secret CHAINGUARD_PULL_TOKEN_USERNAME and enter the username from the previous section.
  4. Select Add secret.
  5. Repeat these steps to create CHAINGUARD_PULL_TOKEN_PASSWORD with the password value.

To share one token across every repository in your GitHub organization, add the secrets at Settings > Secrets and variables > Dependabot in the organization’s settings instead, and grant access to the repositories that need them.

Configure Dependabot

Create a file named .github/dependabot.yml at the root of your repository with the following content:

version: 2

registries:
  chainguard:
    type: docker-registry
    url: cgr.dev
    username: ${{secrets.CHAINGUARD_PULL_TOKEN_USERNAME}}
    password: ${{secrets.CHAINGUARD_PULL_TOKEN_PASSWORD}}
    replaces-base: true

updates:
  - package-ecosystem: "docker"
    directory: "/"
    registries:
      - chainguard
    schedule:
      interval: "daily"

This configuration defines a registry named chainguard, points it at cgr.dev, and authenticates with the secrets you created. The updates section tells Dependabot to check the Dockerfiles in the repository root once a day, using that registry.

Adjust directory to match where your manifests live, and interval to match how often you want pull requests. Refer to GitHub’s Dependabot options reference for the full set of options.

Commit this file to your repository’s default branch.

Understanding replaces-base

Setting replaces-base: true tells Dependabot to resolve container image references against cgr.dev instead of Docker Hub, the default registry for the Docker ecosystem.

This setting doesn’t affect fully qualified references such as cgr.dev/example.com/go:1.22, which Dependabot matches by hostname either way. It changes how Dependabot resolves unqualified references such as FROM python:3.13, which it sends to cgr.dev rather than Docker Hub.

Keep replaces-base: true when every container image in the repository comes from Chainguard. If the repository also pulls images from other registries, omit the setting so Dependabot resolves each reference against the registry that hosts it:

registries:
  chainguard:
    type: docker-registry
    url: cgr.dev
    username: ${{secrets.CHAINGUARD_PULL_TOKEN_USERNAME}}
    password: ${{secrets.CHAINGUARD_PULL_TOKEN_PASSWORD}}

Verify the configuration

Dependabot runs on the schedule you set, but you can trigger a run immediately to confirm that authentication works:

  1. In your repository on GitHub, go to Insights > Dependency graph > Dependabot.
  2. Find the entry for the docker ecosystem.
  3. Select Check for updates.

Select Last checked to open the job log. A successful run lists the tags Dependabot found for each image, then opens a pull request for any reference it can update, with a title such as Bump example.com/go from 1.22 to 1.26.

Update digest-pinned references

Chainguard recommends pinning image references to a digest while keeping the tag as a version hint, in the form cgr.dev/example.com/go:1.22@sha256:.... Dependabot updates both parts of a reference that’s already in this form, as described in Unique tags.

Two limits are worth knowing before you rely on this:

  • Dependabot updates a digest that’s already present, but it won’t add one to a reference that has only a tag. Pin the digest yourself the first time. Adding digests automatically is an open feature request.
  • When a reference carries both a tag and a digest, Dependabot doesn’t supersede an open pull request as newer digests are published. Because Chainguard rebuilds container images daily, use Digestabot for references pinned to a fixed tag.

Limitations

  • Assumable identities aren’t supported. Dependabot’s OIDC authentication covers a fixed set of registries that doesn’t include Chainguard, so a pull token is the only option. Refer to GitHub’s documentation on configuring access to private registries for the current list.
  • GitHub-hosted Dependabot only. Chainguard tests this configuration against Dependabot as hosted by GitHub. Self-hosted and third-party runners may handle credentials differently.

Troubleshooting

Authentication fails with private_source_authentication_failure

This error means Dependabot reached cgr.dev but couldn’t authenticate. Check the following, in order:

  1. Confirm the secrets are stored under Dependabot, not Actions. This is the most common cause.
  2. Confirm the pull token is still valid. Run chainctl auth pull-token list to see the tokens in your organization and when they expire.
  3. Confirm the username is the complete <organization ID>/<pull token ID> string, including the slash.
  4. Test the credentials outside of Dependabot with docker login cgr.dev --username <USERNAME> --password <PASSWORD>, followed by a docker pull of one of the images in your repository.

No pull requests appear

If the job log shows a successful run but no pull requests, check the following:

  • Dependabot acts on the tag string. A reference pinned to a mutable tag such as latest produces no pull requests, because the tag never changes. Use Digestabot for those references.
  • Dependabot opens at most five pull requests per ecosystem by default. Raise the open-pull-requests-limit option if existing pull requests are holding the queue.
  • Unqualified references such as FROM python:3.13 reach cgr.dev only when replaces-base: true is set. Otherwise, fully qualify the reference.

Learn more

Last updated: 2026-09-03 15:15