Answer architecture round 1: 0 🔴, 3 🟡; copy the image to Docker Hub in a job of its own, give the registries their own decision, and name the narrowest token

This commit is contained in:
2026-10-14 11:18:32 +02:00
committed by Lillem4n
parent f3fbbac0d9
commit 508e93d11a
7 changed files with 58 additions and 31 deletions
+30 -10
View File
@@ -13,8 +13,6 @@ on:
required: true
PACKAGES_RSA_KEY:
required: true
DOCKERHUB_USERNAME:
required: true
DOCKERHUB_TOKEN:
required: true
workflow_dispatch:
@@ -79,10 +77,6 @@ jobs:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: goreleaser/goreleaser-action@v7
with:
version: v2.18.3
@@ -91,14 +85,40 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
- name: The built binary and the published images print the tag
- name: The built binary and the published image print the tag
env:
TAG: ${{ inputs.tag }}
run: |
test "$(dist/fejkdata_linux_amd64_v1/fejkdata --version)" = "fejkdata $TAG"
for image in docker.io/larvit/fejkdata ghcr.io/larvit/fejkdata; do
test "$(docker run --rm "$image:${TAG#v}" --version)" = "fejkdata $TAG"
done
test "$(docker run --rm "ghcr.io/larvit/fejkdata:${TAG#v}" --version)" = "fejkdata $TAG"
dockerhub:
name: Docker Hub image for ${{ inputs.tag }}
needs: packages
runs-on: ubuntu-26.04
permissions:
packages: read
steps:
- uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/login-action@v4
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Copy the GHCR image to Docker Hub, and check it prints the tag
env:
LATEST: ${{ needs.packages.outputs.latest }}
TAG: ${{ inputs.tag }}
run: |
tags=(-t "docker.io/larvit/fejkdata:${TAG#v}")
if [ "$LATEST" = true ]; then
tags+=(-t docker.io/larvit/fejkdata:latest)
fi
docker buildx imagetools create "${tags[@]}" "ghcr.io/larvit/fejkdata:${TAG#v}"
test "$(docker run --rm "docker.io/larvit/fejkdata:${TAG#v}" --version)" = "fejkdata $TAG"
repos:
name: apt, dnf and apk repositories for ${{ inputs.tag }}
-1
View File
@@ -99,5 +99,4 @@ jobs:
TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
PACKAGES_GPG_KEY: ${{ secrets.PACKAGES_GPG_KEY }}
PACKAGES_RSA_KEY: ${{ secrets.PACKAGES_RSA_KEY }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
+1
View File
@@ -123,6 +123,7 @@ In [docs/decisions.md](docs/decisions.md):
- The locales are Ethnologue 2026's ten most-spoken languages, each in the country with the most speakers of it, the Nordic countries and Germany
- A country with no open address register covering it whole ships its places and postal codes without streets
- The apt, dnf and apk repositories are static files on GitHub Pages, holding the latest release only
- The image is pushed to GHCR and copied to Docker Hub, whose name the README shows
# Scoring run
+1 -1
View File
@@ -9,7 +9,7 @@ replacement, and each removed path, column or flag.
### Added
- Prebuilt binaries for Linux, macOS and Windows on amd64 and arm64, packages for apt,
dnf, apk, Homebrew and Scoop, and the image `larvit/fejkdata` on Docker Hub and GHCR, so
dnf, apk, Homebrew and Scoop, and the image `larvit/fejkdata` on Docker Hub, also at `ghcr.io/larvit/fejkdata`, so
the CLI installs without Go. 0.1.0 ships them too; the README's
[Install](https://github.com/larvit/fejkdata#install) lists each command.
+13 -12
View File
@@ -42,8 +42,8 @@ docker run --rm -i larvit/fejkdata < template.json # any OS with
go install github.com/larvit/fejkdata/cmd/fejkdata@latest # any OS with Go
```
The image is also `ghcr.io/larvit/fejkdata`, which CI on shared runners may prefer:
Docker Hub limits anonymous pulls per IP address.
On shared CI runners, pull `ghcr.io/larvit/fejkdata` instead: Docker Hub limits anonymous
pulls per IP address.
Debian, Ubuntu, Fedora, RHEL and Alpine install from fejkdata's signed repositories, which
hold the latest release:
@@ -1280,21 +1280,22 @@ To release, head `CHANGELOG.md` with the version's section in place of `Unreleas
and merge: once `main` passes the gate, CI tags that commit `vX.Y.Z` and publishes
the GitHub release with the section as its body. A top heading of `[Unreleased]`
publishes nothing. CI then runs the Packages workflow on the new tag, which attaches the
binaries and packages, pushes the image to Docker Hub and GHCR, updates the Homebrew tap and the Scoop bucket,
and deploys the apt, dnf and apk repositories to GitHub Pages. The workflow reads
these repository secrets:
binaries and packages, pushes the image to GHCR and copies it to Docker Hub, updates the
Homebrew tap and the Scoop bucket, and deploys the apt, dnf and apk repositories to GitHub
Pages. The workflow reads these repository secrets:
- `DOCKERHUB_USERNAME`, `DOCKERHUB_TOKEN`: a Docker Hub account and access token that can
push to `larvit/fejkdata`.
- `DOCKERHUB_TOKEN`: a Docker Hub access token with Read & Write and no Delete, or an
organization token that can push only to `larvit/fejkdata`. The repository variable
`DOCKERHUB_USERNAME` names its account.
- `PACKAGES_GPG_KEY`, `PACKAGES_RSA_KEY`: the private keys that sign the repositories.
- `TAP_GITHUB_TOKEN`: a token that can push to `larvit/homebrew-tap` and
`larvit/scoop-bucket`.
The image's Docker Hub repository and GHCR package must be public, and Pages must deploy from GitHub Actions. To
package a release again,
run the workflow by hand with its tag; it replaces what it uploaded before. For a tag older
than the latest release it leaves the tap, the bucket, the images' `latest` and
the repositories alone, since each holds one version.
The image's Docker Hub repository and GHCR package must be public, and Pages must deploy
from GitHub Actions. To package a release again, run the workflow by hand with its tag; it
replaces what it uploaded before. For a tag older than the latest release it leaves the
tap, the bucket, the image's `latest` tags and the repositories alone, since each holds one
version.
## License
+13 -6
View File
@@ -903,7 +903,7 @@ By the maintainer's decision of 2026-10-09, every 0.1.0 chunk ships under the fl
Shipped under that decision: item 89, the last of 0.1.0, at 52e0304. Its paired ruling against 90ffcff was better. The release's scoring run read Navigation 7.00, Locality 5.75, Shape 6.38, Self-sufficiency 6.50 and overall 6.25; its seats named places items 170 to 172 and 178 hold, and `isPath`, filed as item 251.
Shipped under the floor by the maintainer's decision of 2026-10-13: item 58, prebuilt binaries and packages, which the plan had under 0.2.0, ships as 0.1.0's distribution, and so does the image on Docker Hub, decided 2026-10-14. Neither changes Go code.
Shipped under the floor as 0.1.0's distribution, each by the maintainer's decision: item 58, prebuilt binaries and packages, which the plan had under 0.2.0, on 2026-10-13; and the image on Docker Hub, on 2026-10-14. Neither changes Go code.
Shipped by the maintainer's decision of 2026-10-11 with its ratchet waived: item 182, the shipped data as Go packages, at a632a92. Its last paired ruling against bf1becb was same overall, Mid A better and Junior A worse, with Shape fallen, three seats against the namespace mount in `internal/datafiles/mount.go` and the `at` field of `datafiles.Source`; the scoring run that would rule it worse under the floor was not run. `todo.md` item 197 replaces that mount.
@@ -970,13 +970,20 @@ vendor-neutral option (`~/.claude/principles/technical-principles.md`). The repo
are built here, as static files any host can serve: `release-tooling/package-repos.Dockerfile`
signs them with a GPG key (apt, dnf) and an RSA key (apk). A hosted package service would
only save that tooling. GitHub already hosts the code (see "GitHub is canonical, and the
module path names it"), so Pages adds no new vendor. The image sits on GHCR for the same
reason; being OCI, it moves to another registry by changing its path. Docker Hub carries
the same image too, by the maintainer's decision of 2026-10-14: it is Docker's default
registry, so `docker run larvit/fejkdata` works with no host in the name. Docker Hub limits
anonymous pulls by IP, so CI on shared runners may pull from `ghcr.io` instead. A Pages site holds at
module path names it"), so Pages adds no new vendor. A Pages site holds at
most 1 GB and a release's packages take about 35 MB, so the repositories hold the latest
release only; each GitHub release still carries its own packages, and the image keeps a tag
per version. Leaving Pages costs
each Linux user an edit: their apt list, `.repo` file or apk line names `larvit.github.io`.
Valid while GitHub hosts the code.
## The image is pushed to GHCR and copied to Docker Hub, whose name the README shows
2026-10-14, decided by the maintainer. Serves goal 1.1; technical principle: prefer the
vendor-neutral option (`~/.claude/principles/technical-principles.md`). Docker Hub is
Docker's default registry, so `docker run larvit/fejkdata` works with no host in the name;
that is a capability only Docker Hub has. GHCR stays the image's source: GoReleaser pushes
there, and a job of its own copies the image to Docker Hub, so a Docker Hub failure holds up
no other channel. GHCR also serves CI on shared runners, which Docker Hub's per-IP limit on
anonymous pulls blocks. Leaving Docker Hub costs each user an edit of every `docker run` line
and pinned script that names the bare `larvit/fejkdata`.
-1
View File
@@ -54,7 +54,6 @@ nfpms:
dockers_v2:
- images:
- docker.io/larvit/fejkdata
- ghcr.io/larvit/fejkdata
tags:
- "{{ .Version }}"