diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e54287..a5dd89b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## build tooling — the golden bakes EVERY infra image, asked from the controller (2026-07-19) + +**No agent version bump: `configs/build-golden.sh` only (v2.0.0 → v2.1.0). Effective at the NEXT +golden build — the current golden is NOT rebuilt for this.** + +- **The bug, observed live twice.** Enabling Megosztás on a fresh box pulled `felhom-samba` from the + registry with zero feedback: minutes of silent nothing. Cause: this script carried its own + hand-maintained array of three image tags, with a comment instructing the reader to keep it in sync + with the controller's `internal/infra` constants. It drifted the moment a fourth stack was added — + `felhom-samba` was never added here, so the golden baked **3 of 4**. +- **The fix is structural, not another copy.** The list now comes from the controller image the bake + just pulled: `docker run --rm --print-infra-images` (backed by `infra.Images()`, which + derives from the pins themselves). The golden therefore bakes exactly what **that** controller + version will request, and the two cannot disagree by construction. A controller-side test parses + the const block out of the source and fails if a pin is added without reaching `Images()`. +- **Ordering fix that this exposed.** `docker logout` + `config.json` removal ran immediately after + the controller pull. `felhom-samba` lives on the **same private registry**, so the infra loop would + have 401'd. The logout moved to **after** the loop, with an added hard assertion that no credential + remains in the guest before it is archived — the credential is still never baked. +- **Fallback, loudly.** A controller older than v0.147.0 has no `--print-infra-images`; the bake falls + back to the historical 3-image list and prints three WARN lines saying felhom-samba will not be + baked and Megosztás will pull at runtime. The fallback is exactly the drift-prone thing this change + removes, so it announces itself rather than passing silently. +- **ROADMAP:** golden **≥ 0.147.x** carries all four infra images. + ## v0.90.1 — R-39 hotfix: PBS reconcile must not pass `--server` to `pvesm set` (2026-07-18) **Config-only fix (wrapper + red-proof); the Go binary is unchanged.** Ship the wrapper with the diff --git a/configs/build-golden.sh b/configs/build-golden.sh index 9f57f60..73997fd 100644 --- a/configs/build-golden.sh +++ b/configs/build-golden.sh @@ -39,7 +39,7 @@ set -euo pipefail # Script provenance — logged into every bake transcript next to the baked controller tag, so an # archive can always be traced to the script that produced it. Bump on any behavior change. -GOLDEN_SCRIPT_VERSION="2.0.0" +GOLDEN_SCRIPT_VERSION="2.1.0" VMID="${1:-9100}" TEMPLATE="${2:-local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst}" @@ -136,29 +136,52 @@ if [ -n "${REGISTRY_USER:-}" ] && [ -n "${REGISTRY_TOKEN:-}" ]; then pct exec "$VMID" -- bash -c "systemctl start docker; sleep 1; echo '$REGISTRY_TOKEN' | docker login '$REGISTRY_HOST' -u '$REGISTRY_USER' --password-stdin >/dev/null" fi pct exec "$VMID" -- bash -c "docker pull '$CONTROLLER_IMAGE'" -pct exec "$VMID" -- bash -c "docker logout '$REGISTRY_HOST' >/dev/null 2>&1 || true; rm -f /root/.docker/config.json" # Record the baked image ref for the bootstrap unit (so the unit needs no login/pull). pct exec "$VMID" -- bash -c "printf '%s\n' '$CONTROLLER_IMAGE' > /etc/felhom-controller-image" -# Bake the base-infrastructure images (traefik, cloudflared, filebrowser) so the controller's -# first-boot bring-up (EnsureBaseStack) is OFFLINE-capable — no registry pull at deploy. These are -# PUBLIC Docker Hub images (no cred needed). The PINNED tags MUST match the controller's -# internal/infra constants (TraefikImage / CloudflaredImage / FileBrowserImage); a drift means the -# golden bakes one image and the controller requests another (→ a pull at deploy, defeating the goal). -INFRA_IMAGES=( - "traefik:v3.6.7" - "cloudflare/cloudflared:2026.6.0" - "gtstef/filebrowser:1.3.3-stable" -) -echo "[golden] baking base-infra images: ${INFRA_IMAGES[*]} …" +# Bake EVERY controller-managed infra image so enabling an infra stack on a fresh box is near-instant +# instead of a multi-minute silent registry pull. +# +# THE LIST COMES FROM THE CONTROLLER WE JUST PULLED, not from a copy here. This script used to carry +# a hand-maintained array of three tags with a comment telling the reader to keep it in sync with the +# controller's internal/infra constants. It drifted the moment a fourth stack was added: felhom-samba +# was never added here, so the golden baked 3 of 4 and turning on Megosztás pulled from the registry +# with zero UI feedback — observed live, twice. Asking the binary (`--print-infra-images`, backed by +# infra.Images()) makes golden-vs-controller drift structurally impossible: the golden bakes exactly +# what THIS controller version will request. +echo "[golden] asking the controller which infra images it manages …" +INFRA_LIST="$(pct exec "$VMID" -- bash -c "docker run --rm --entrypoint /usr/local/bin/felhom-controller '$CONTROLLER_IMAGE' --print-infra-images 2>/dev/null" || true)" +mapfile -t INFRA_IMAGES < <(printf '%s\n' "$INFRA_LIST" | grep -E '^[a-z0-9._/-]+:[A-Za-z0-9._-]+$' || true) +if [ "${#INFRA_IMAGES[@]}" -eq 0 ]; then + # Controllers older than v0.147.0 have no --print-infra-images. Fall back to the historical list so + # an old-controller bake still works — but say so loudly, because the fallback is exactly the + # drift-prone thing this change removed, and it CANNOT know about stacks added after it was written. + echo "[golden] WARN: '$CONTROLLER_IMAGE' does not support --print-infra-images (pre-0.147.0)." + echo "[golden] WARN: falling back to the historical 3-image list. felhom-samba will NOT be baked," + echo "[golden] WARN: so enabling Megosztás on this golden will pull at runtime. Bake >=0.147.0." + INFRA_IMAGES=( + "traefik:v3.6.7" + "cloudflare/cloudflared:2026.6.0" + "gtstef/filebrowser:1.3.3-stable" + ) +fi +echo "[golden] baking infra images (${#INFRA_IMAGES[@]}): ${INFRA_IMAGES[*]} …" for img in "${INFRA_IMAGES[@]}"; do # Hard gate: fail loudly BEFORE pulling if a pinned tag doesn't resolve (a bad pin otherwise fails # mid-bake with a confusing error). pct exec "$VMID" -- bash -c "docker manifest inspect '$img' >/dev/null 2>&1" \ - || { echo "[golden] FATAL: pinned base-infra image does not resolve: $img"; exit 1; } + || { echo "[golden] FATAL: pinned infra image does not resolve: $img"; exit 1; } pct exec "$VMID" -- bash -c "docker pull '$img'" done +# Log out LAST — not right after the controller pull. felhom-samba lives on the same private registry +# as the controller, so the infra loop above needs the credential; logging out first made that pull +# 401. The credential is still never archived: the logout + config.json removal happen before the +# guest is stopped and templated. +pct exec "$VMID" -- bash -c "docker logout '$REGISTRY_HOST' >/dev/null 2>&1 || true; rm -f /root/.docker/config.json" +pct exec "$VMID" -- bash -c '[ ! -s /root/.docker/config.json ]' \ + || { echo "[golden] FATAL: registry credential still present in the guest — refusing to archive"; exit 1; } + echo "[golden] baking the controller-bootstrap unit (deploys the BAKED controller from the config mount) …" pct push "$VMID" /dev/stdin /usr/local/sbin/felhom-controller-bootstrap.sh --perms 700 <<'BOOTSH' #!/bin/bash