feat: address the review on the image publicity gate by passing build-push only the seven services that workflow actually publishes, since web, admin and cli have no :dev tag and would have warned falsely on every push to main, by taking the release tag through the step env instead of interpolating github.ref_name into the shell, and by no longer asserting the tag is fine when a pull is refused, because GHCR denies an unknown namespace exactly as it denies a private one, so a mistyped --registry now gets its own reading in the installer message, the troubleshooting table and the fork note, which also splits the personal and organization paths to the visibility setting

This commit is contained in:
Matthew Meszaros
2026-09-07 09:02:23 -07:00
parent 719a81866c
commit c4bfbaf4a9
7 changed files with 30 additions and 13 deletions
+6 -1
View File
@@ -274,5 +274,10 @@ jobs:
contents: read
steps:
- uses: actions/checkout@v4
# Only what this workflow publishes. web, admin and cli are built at
# tag time and have no :dev tag, so checking them here would warn about
# something no push to main can fix.
- name: Pull-test every image anonymously
run: ./scripts/check-images-public.sh --prefix "$IMAGE_PREFIX" --tag dev --warn
run: |
./scripts/check-images-public.sh --prefix "$IMAGE_PREFIX" --tag dev --warn \
backend consumer worker forms updater tracking realtime
+3 -1
View File
@@ -287,7 +287,9 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Pull-test every image anonymously
run: ./scripts/check-images-public.sh --prefix "$IMAGE_PREFIX" --tag "${{ github.ref_name }}"
env:
TAG: ${{ github.ref_name }}
run: ./scripts/check-images-public.sh --prefix "$IMAGE_PREFIX" --tag "$TAG"
create-release:
name: Create GitHub Release
@@ -752,7 +752,7 @@ CI publishes multi-arch images to `ghcr.io/<owner>/warmbly/`, which works on any
| Push to `main` | backend, consumer, worker, forms, updater, tracking, realtime | `:<sha>`, `:dev` |
| Tag `vX.Y.Z` | all of the above plus web and admin | `:vX.Y.Z`, `:vX.Y`, `:vX`, `:prod` |
One thing to know if you are running a fork: GHCR creates each package private and does not inherit your repository's visibility, so images published by a green workflow are still unreadable to anyone else until an owner makes each package public by hand under Packages in the org settings. There is no API for it. `make images-check` tells you where a given tag stands, with no credentials, which is the same check the release runs before it publishes.
One thing to know if you are running a fork: GHCR creates each package private and does not inherit your repository's visibility, so images published by a green workflow stay unreadable to everyone else until you make each package public by hand. On a personal fork that is the package's own settings page, reached from the Packages tab on your profile. On an organization fork it is the same page reached from the org's Packages, and public packages have to be permitted in the org's package settings first, or the control is greyed out. There is no API for either. `make images-check` tells you where a given tag stands, with no credentials, and it is the same check the release runs before it publishes.
Every app service in `docker-compose.yml` carries both an `image:` and a `build:` key, so the same file serves both paths. `docker compose pull && docker compose up -d` runs the published images and compiles nothing; `docker compose up --build` still builds this checkout. Pin a release with `WARMBLY_TAG=v1.4.2` in `.env`, or point `WARMBLY_IMAGE_PREFIX` at your own registry.
+1 -1
View File
@@ -305,7 +305,7 @@ Stops and removes the containers and leaves every byte of data where it is. Addi
| `Docker is installed but not answering` | The daemon is not running, or your user is not in the `docker` group yet. `sudo systemctl start docker`, then log out and back in |
| `Something already listens on 3000` | Another self-hosted tool. Change the published port in `docker-compose.yml` before starting |
| `Could not pull the release images` | The tag does not exist, or this host cannot reach `ghcr.io`. Check [releases](https://github.com/warmbly/warmbly/releases) |
| `The registry refused to serve the release images` | The images are not readable without an account, which is never how a release is meant to ship. Please [report it](https://github.com/warmbly/warmbly/issues). To get past it now, `docker login ghcr.io` or point `--registry` at a mirror |
| `The registry refused to serve the release images` | The images are not readable without an account, which is never how a release is meant to ship. Please [report it](https://github.com/warmbly/warmbly/issues). If you passed `--registry`, check it for a typo first: a namespace that does not exist is refused the same way. To get past it, point `--registry` at a mirror you can read, or `docker login ghcr.io` as someone who already has access to the packages. Logging in does not by itself grant it |
| The API never answers | The first boot applies every migration. `docker compose -p warmbly logs -f backend` |
| No claim link printed | The database already has accounts, so there is nothing to claim. See [first run](/development/first-run/) |
+6 -1
View File
@@ -198,16 +198,21 @@ STUB
printf 'Error response from daemon: Head "https://ghcr.io/v2/warmbly/warmbly/forms/manifests/v0.4.0": unauthorized\n' >"$work/log.unauth"
printf 'Error response from daemon: manifest unknown\n' >"$work/log.missing"
printf 'Error response from daemon: denied\n' >"$work/log.denied"
diag "$work/log.unauth" | grep -q 'refused to serve' ||
fail "an unauthorized pull is not diagnosed as a registry refusal"
diag "$work/log.unauth" | grep -q 'is not the problem' ||
diag "$work/log.unauth" | grep -q 'probably fine' ||
fail "an unauthorized pull still blames the tag"
diag "$work/log.unauth" | grep -q 'check it for a typo' ||
fail "an unauthorized pull does not mention a mistyped --registry, which"
diag "$work/log.missing" | grep -q 'may not exist' ||
fail "an ordinary pull failure lost its generic message"
if diag "$work/log.missing" | grep -q 'refused to serve'; then
fail "an ordinary pull failure is misreported as a registry refusal"
fi
diag "$work/log.denied" | grep -q 'check it for a typo' ||
fail "a bare denied does not offer the mistyped-registry reading"
pass "diagnoses an unauthorized pull separately from a missing tag"
# The checksum is the whole answer to "why would I pipe this into a shell", so
+12 -7
View File
@@ -2284,15 +2284,20 @@ pull_failed() {
grep -Eqi 'unauthorized|denied|authentication required' "$LOGFILE"; then
_host=${REGISTRY%%/*}
fail_with "The registry refused to serve the release images." \
"It answered unauthorized, so they are not readable without" \
"an account. The tag ${RESOLVED_TAG} is not the problem." \
"It answered unauthorized rather than 'no such tag', so" \
"${RESOLVED_TAG} is probably fine and the images are simply" \
"not readable without an account." \
"" \
"Every Warmbly image is meant to be public. If this is the" \
"published registry, that is our bug, not yours: please tell" \
"us at https://github.com/$REPO/issues" \
"Every Warmbly image is meant to be public. If you did not" \
"pass --registry, that makes this our bug, not yours:" \
"please tell us at https://github.com/$REPO/issues" \
"" \
"To get past it now: docker login $_host, or point --registry" \
"at a mirror this host can read."
"If you did pass it, check it for a typo. A namespace that" \
"does not exist is refused in exactly the same way as a" \
"private one." \
"" \
"To get past it now: docker login $_host as someone who can" \
"read these images, or point --registry at a mirror you can."
fi
fail_with "Could not pull the release images." \
"The tag ${RESOLVED_TAG} may not exist, or this host cannot" \
+1 -1
View File
@@ -1 +1 @@
861af096a6e3c520ad0172ca039f376a916aea6c820bff34da66c21ea87d689c install.sh
19ce4203d82b086fd65e30bbd63758364370f154979b664f453842327c67ecb6 install.sh