CI/CD Workflow Authentication#
Overview#
Authentication in this repo's CI/CD pipelines is split across three credential types — a GitHub App token (otelbot), the built-in GITHUB_TOKEN, and a DockerHub access token — with strict boundaries on which token is used for which operation. Understanding these boundaries is critical because the wrong token at the wrong step will silently produce a permission error.
Token Reference#
| Credential | Secret/Var | Used For |
|---|---|---|
| otelbot GitHub App | OTELBOT_COLLECTOR_RELEASES_CLIENT_ID (var) + OTELBOT_COLLECTOR_RELEASES_PRIVATE_KEY (secret) | Git push, tag creation/deletion |
GITHUB_TOKEN | secrets.GITHUB_TOKEN | GHCR login (push images), GHCR package version deletion |
| DockerHub token | vars.DOCKER_USERNAME + secrets.DOCKER_TOKEN_COLLECTOR_RELEASES | Docker Hub image push and nightly tag deletion |
otelbot App Token vs. GITHUB_TOKEN#
The otelbot GitHub App token is used only for Git operations — checkout, tag creation, and tag deletion. It is explicitly not used for container registry operations because the otelbot installation is not granted the packages permission; attempting to request it causes the token creation step to fail with:
The permissions requested are not granted to this installation
This is documented in a comment in cleanup-nightly.yaml and was the root cause of failures addressed in PR #1614.
Split in practice:
- Git tag deletion in
cleanup-nightly-git-tags.shruns via agit push origin --deleteauthenticated with the otelbot token (checked out withtoken: ${{ steps.otelbot-token.outputs.token }}). - GHCR package version deletion in
cleanup-nightly-ghcr.shusesGH_TOKEN: ${{ secrets.GITHUB_TOKEN }}withpackages: writegranted at the job level.
GHCR Package Deletion Authorization#
Deleting GHCR package versions requires packages: write in both the calling workflow and any workflow_call child. In nightly-release.yaml, the cleanup-nightly job explicitly re-grants this permission when invoking the reusable workflow — without it, the permission would be capped away:
permissions:
contents: read
packages: write
The reusable cleanup-nightly.yaml also declares packages: write at the job level . If either declaration is missing, the gh api DELETE call in the cleanup script will fail with a 403.
The GHCR cleanup script authenticates via GH_TOKEN and calls the GitHub Packages API (/orgs/{ORG}/packages/container/{PACKAGE}/versions), filtering to versions whose tags all match the vX.Y.Z-nightly.<ts> pattern and whose updated_at is older than 2 weeks.
For image push during a release, GHCR login uses secrets.GITHUB_TOKEN wrapped in a retry action (5 attempts, 15 s delay) to guard against transient registry errors.
DockerHub Token History#
DockerHub authentication went through a turbulent cycle:
- Legacy: workflows used
secrets.DOCKER_USERNAME+secrets.DOCKER_PASSWORD. - PR #1031 re-enabled a new token (
DOCKER_TOKEN_COLLECTOR_RELEASES) withvars.DOCKER_USERNAME. - PR #1050 reverted — the new token lacked sufficient DockerHub permissions at that time.
- PR #1057 re-introduced the new token after the necessary DockerHub permissions were added.
Current state: all release workflows (base-release.yaml, release-builder.yaml, release-opampsupervisor.yaml) and the nightly cleanup authenticate to Docker Hub with vars.DOCKER_USERNAME + secrets.DOCKER_TOKEN_COLLECTOR_RELEASES.
The DockerHub cleanup script exchanges these credentials for a short-lived Hub JWT via POST /v2/users/login/ and fails fast if the response token is empty or null.
Workflow Permission Propagation#
A subtle GitHub Actions rule: when a top-level workflow calls a reusable workflow with uses:, the child's GITHUB_TOKEN is capped by the permissions declared in the calling job block. nightly-release.yaml must therefore explicitly grant packages: write when invoking cleanup-nightly.yaml, or GHCR deletion will be denied — even though the child workflow also declares packages: write internally. The same applies to secrets: inherit for DockerHub credentials.
Key Files#
| File | Purpose |
|---|---|
.github/workflows/cleanup-nightly.yaml | Reusable cleanup workflow; defines per-job token strategy |
.github/workflows/nightly-release.yaml | Nightly trigger; must re-grant packages: write to child |
.github/workflows/scripts/cleanup-nightly-ghcr.sh | GHCR package version deletion via GitHub API |
.github/workflows/scripts/cleanup-nightly-dockerhub.sh | DockerHub tag deletion via Hub API + JWT |
.github/workflows/scripts/cleanup-nightly-git-tags.sh | Git tag deletion via otelbot-authenticated push |