From 42af07c255078b0bca072c487c6cab12512f5843 Mon Sep 17 00:00:00 2001 From: lilleman Date: Sat, 22 Aug 2026 14:27:31 +0200 Subject: [PATCH] Use one Docker Hub credential for images and the overview --- .gitea/workflows/release.yml | 4 ++-- README.md | 6 ++---- release-tooling/dockerhub-overview.ts | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 471bcff..975d9c5 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -88,8 +88,8 @@ jobs: ref: refs/tags/v${{ inputs.overview_version }} - name: Publish the Docker Hub overview env: - DOCKERHUB_OVERVIEW_TOKEN: ${{ secrets.DOCKERHUB_OVERVIEW_TOKEN }} DOCKERHUB_REPO: ${{ github.repository }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} DOCKERHUB_USER: ${{ vars.DOCKERHUB_USER }} GIT_TAG: ${{ github.ref_name }} INPUT_VERSION: ${{ inputs.overview_version }} @@ -101,6 +101,6 @@ jobs: docker run --rm -v "$PWD:/repo" -w /repo node:24.19.0-alpine3.24 \ node release-tooling/contract-version.ts "$VERSION" src/plugin-host/plugin.ts docker run --rm -v "$PWD:/repo" -w /repo \ - -e DOCKERHUB_OVERVIEW_TOKEN -e DOCKERHUB_REPO -e DOCKERHUB_USER \ + -e DOCKERHUB_REPO -e DOCKERHUB_TOKEN -e DOCKERHUB_USER \ node:24.19.0-alpine3.24 \ node release-tooling/dockerhub-overview.ts "$VERSION" diff --git a/README.md b/README.md index 838ce49..8ecec03 100644 --- a/README.md +++ b/README.md @@ -1424,8 +1424,7 @@ outage leaves the promotion green and the images untouched; and the page has its workflow manually with an `overview_version` input to republish it without cutting a release. That input goes through the same contract check as a tag: a non-semver value, or one whose `major.minor` disagrees with the tree being published, is refused. It uses -`DOCKERHUB_OVERVIEW_TOKEN`, separate from the image-push token because editing repository metadata is -a different permission and widening the push credential to cover it would widen what a leak costs. +the same `DOCKERHUB_TOKEN` the image push uses, which is why that token needs the **delete** scope. **GitHub mirror** — [github.com/larvit/plainpages](https://github.com/larvit/plainpages) is read-only; after every merge `mirror.yml` force-pushes `main` and all tags, overwriting any drift. @@ -1462,8 +1461,7 @@ the built-in Actions token wouldn't trigger it). `HOST_API_VERSION` is never tou | Actions var / secret | Value | | --- | --- | | `DOCKER_REGISTRY_USER` (var) + `DOCKER_REGISTRY_TOKEN` (secret) | A Gitea account with package write in the `larvit` org, and its access token with `read:package` + `write:package`. Reused by `registry-cleanup.yml`. | -| `DOCKERHUB_USER` (var) + `DOCKERHUB_TOKEN` (secret) | The public `larvit/plainpages` Docker Hub repo, and a read/write token **scoped to that repository** (an org access token, or one on a dedicated account — an account-wide PAT can push to every repo under it). | -| `DOCKERHUB_OVERVIEW_TOKEN` (secret) | A Docker Hub PAT with **read/write/delete** scope — editing the overview needs delete, pushing images does not. Kept separate so that scope never reaches `docker login`, which writes it to the runner's shared config; without it the `publish-overview` job fails and the released images are unaffected. | +| `DOCKERHUB_USER` (var) + `DOCKERHUB_TOKEN` (secret) | The public `larvit/plainpages` Docker Hub repo, and a **read/write/delete** token **scoped to that repository** (an org access token, or one on a dedicated account — an account-wide PAT reaches every repo under it, and delete is destructive). Delete is what publishing the overview needs; pushing images alone would not. | | `MIRROR_GITHUB_TOKEN` (secret) | A fine-grained PAT (Contents: read & write) for a GitHub machine account with write access to the mirror. Its `main` must not block force-pushes and must carry no tag protection, which would reject the prune. | | `RENOVATE_TOKEN` (secret) | The shared `renovate@larvit.se` bot's Gitea PAT, with write access to this repo. | | `RENOVATE_GITHUB_TOKEN` (secret) | A **scopeless** (read-only) github.com PAT, so Renovate's lookups of github.com-hosted deps run authenticated instead of tripping the anonymous 60-req/hour limit. | diff --git a/release-tooling/dockerhub-overview.ts b/release-tooling/dockerhub-overview.ts index 24da29a..f637c99 100644 --- a/release-tooling/dockerhub-overview.ts +++ b/release-tooling/dockerhub-overview.ts @@ -49,11 +49,11 @@ async function main(): Promise { const [, , version] = process.argv; const repo = process.env["DOCKERHUB_REPO"]; const user = process.env["DOCKERHUB_USER"]; - const token = process.env["DOCKERHUB_OVERVIEW_TOKEN"]; + const token = process.env["DOCKERHUB_TOKEN"]; if (!version || !repo || !user || !token) { return fail( "usage: dockerhub-overview.ts ; needs DOCKERHUB_REPO, DOCKERHUB_USER and " + - "DOCKERHUB_OVERVIEW_TOKEN (README -> CI/CD)", + "DOCKERHUB_TOKEN (README -> CI/CD)", ); } // The page is public, so never render a version that resolves to no image. @@ -90,8 +90,8 @@ async function main(): Promise { return fail( `Docker Hub overview PATCH failed: ${res.status} ${res.text}` + (res.status === 403 - ? "\n403 means DOCKERHUB_OVERVIEW_TOKEN lacks the delete scope — editing the overview needs " + - "read/write/delete, which pushing images does not (README -> CI/CD)." + ? "\n403 means DOCKERHUB_TOKEN lacks the delete scope — editing the overview needs " + + "read/write/delete, which pushing images alone does not (README -> CI/CD)." : ""), ); }