From ceca355493a8f24f33e25d49b7a980e34429f5ec Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Fri, 3 Jul 2026 18:21:21 +0200 Subject: [PATCH] =?UTF-8?q?configs:=20build-golden.sh=20v2.0.0=20=E2=80=94?= =?UTF-8?q?=20mandatory=20controller=20tag=20(B5)=20+=20bootstrap=20.path?= =?UTF-8?q?=20unit=20(B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6 --- CHANGELOG.md | 28 +++++++++++++++++++++++++ configs/build-golden.sh | 45 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 592b9e0..354084f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +## configs: build-golden.sh v2.0.0 — mandatory controller tag + bootstrap .path unit (B5 + B1) (2026-07-03) + +Golden-bake script only — **no agent code, no binary, no agent version bump** (docs/config +precedent). Resolves drill findings B5 + B1 +(`felhom.eu/documentation/audits/DRILL-day0-cleanroom-2026-07-03.md` §9) and closes the stale +backlog note `FOLLOWUP-golden-default-controller-tag.md`. + +- **B5 — `CONTROLLER_IMAGE` (arg 6) is now MANDATORY** — the hand-bumped default rotted twice + (0.43.0 → 0.85.1 → stale again; 0.85.1 predates the v0.86.0 floor-honoring code, which is why + every fresh install needed the manual D.1b update). No 6th arg → die with usage (red-proofed: + exits 1 before any `pct` op). Auto-resolving "latest" was rejected — it could bake an unvouched + tag. +- **B1 — baked `felhom-controller-bootstrap.path` unit** (`PathExists=/etc/felhom-bootstrap/ + bootstrap.json`, enabled next to the service): the service's `ConditionPathExists` is evaluated + only at boot, but the agent back-half hot-plugs the bootstrap mount into the already-running + guest — the path unit starts the service when the file APPEARS, so the controller deploys with + NO reboot (isolated systemd proof + full Day-0 proof on the clean-room drill VM; the installer's + v1.9.1 post-provision reboot is now a redundant belt, kept). `RemainAfterExit=yes` on the service + prevents re-trigger loops; the service itself stays unchanged. +- `GOLDEN_SCRIPT_VERSION` (2.0.0) + a `[golden]` provenance line (script version + baked controller + tag) now open every bake transcript. +- Baked + published with controller **0.98.3**: golden `0.98.3` / + sha256 `b9a02ef1b6f02b9b58babc4c6aad9cf6c053ebdfba116c78c8e7830de757fd01` (Gitea generic package, + 201 + sha round-trip). Clean-room validation: bake integrity (mp0+mp1 included), isolated + hot-plug proof, full local-golden Day-0 install (first boot = 0.98.3, self-update reports + up-to-date, app deploy OK) — evidence: + `felhom.eu/documentation/audits/DRILL-golden-098-2026-07-03.md`. + ## v0.63.0 — B3 + B2: fresh-install fixes — token reload-on-miss + guesthook snippets dir (2026-07-03) The two agent-side gaps the Day-0 clean-room drill surfaced diff --git a/configs/build-golden.sh b/configs/build-golden.sh index 72597b5..9f57f60 100644 --- a/configs/build-golden.sh +++ b/configs/build-golden.sh @@ -20,7 +20,9 @@ # config mount (/etc/felhom-bootstrap/bootstrap.json) — no docker login/pull at deploy. Refreshing # the golden bumps the controller baseline; controller self-update covers in-between drift. # -# Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] [CONTROLLER_IMAGE] +# Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] CONTROLLER_IMAGE +# CONTROLLER_IMAGE is REQUIRED (no default) — pass the released controller tag explicitly, +# e.g. gitea.dooplex.hu/admin/felhom-controller:0.98.3. # Build-time registry login for the controller pull (used ONCE inside the build guest, then logged # out — never baked): set REGISTRY_USER + REGISTRY_TOKEN in the environment. # @@ -35,15 +37,27 @@ # so the archive would carry NO images and provisioned guests would boot imageless. 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" + VMID="${1:-9100}" TEMPLATE="${2:-local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst}" ROOTFS_STORAGE="${3:-local-lvm}" ARCHIVE_STORAGE="${4:-local}" BRIDGE="${5:-vmbr0}" -# Default to the CURRENT controller so an argument-less build is never wildly stale. ALWAYS pass the -# controller version explicitly at each rebuild (this default only bounds the worst case); a future -# `make golden` that resolves the latest pullable tag would remove the need for a hand-bumped default. -CONTROLLER_IMAGE="${6:-gitea.dooplex.hu/admin/felhom-controller:0.85.1}" +# CONTROLLER_IMAGE is MANDATORY — no default. The hand-bumped default rotted twice (0.43.0 → +# 0.85.1 → stale again): each time, a fresh provision would have booted a pre-floor controller +# needing a manual install-day update (drill finding B5). A required argument cannot rot, and +# auto-resolving "latest" could bake a tag the hub manifest never vouched — so the caller states +# the released controller tag explicitly at every rebuild. +CONTROLLER_IMAGE="${6:-}" +if [ -z "$CONTROLLER_IMAGE" ]; then + echo "[golden] FATAL: CONTROLLER_IMAGE (argument 6) is required — pass the released controller tag explicitly." >&2 + echo "Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] CONTROLLER_IMAGE" >&2 + echo " e.g.: build-golden.sh 9100 local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst local-lvm local vmbr0 gitea.dooplex.hu/admin/felhom-controller:0.98.3" >&2 + exit 1 +fi REGISTRY_HOST="${CONTROLLER_IMAGE%%/*}" # OS rootfs size (GiB) and the golden's Docker-data volume size (GiB). Keep GOLDEN_DOCKER_GB just # large enough for the baked images + headroom; provision grows it to the per-customer target. @@ -56,6 +70,7 @@ GOLDEN_DOCKER_GB="${GOLDEN_DOCKER_GB:-16}" # storage-split B3) and the user-data area would silently fall out of PBS coverage. GOLDEN_SYSDATA_GB="${GOLDEN_SYSDATA_GB:-8}" +echo "[golden] build-golden.sh v${GOLDEN_SCRIPT_VERSION} — baking controller ${CONTROLLER_IMAGE}" echo "[golden] creating build LXC $VMID (nesting=1,keyctl=1, unprivileged; rootfs ${OS_SIZE_GB}G + Docker-data ${GOLDEN_DOCKER_GB}G @ /var/lib/docker + user-data ${GOLDEN_SYSDATA_GB}G @ /mnt/sys_drive, both backup=1) …" pct create "$VMID" "$TEMPLATE" \ --hostname felhom-golden --unprivileged 1 \ @@ -217,6 +232,26 @@ WantedBy=multi-user.target UNIT systemctl enable felhom-controller-bootstrap.service' +# B1 (DRILL-day0-cleanroom-2026-07-03 R6/B1): the service's ConditionPathExists is evaluated only +# when the service is STARTED — i.e. at boot via multi-user.target — but the agent back-half +# hot-plugs the bootstrap mount into the ALREADY-RUNNING guest, so on a provision the boot-time +# start races the mount and loses on slow hardware. This path unit watches for bootstrap.json and +# starts the service when it APPEARS — covering the provision hot-plug without a reboot. The boot +# case is still served by the enabled service itself; RemainAfterExit=yes on the service means the +# path unit cannot re-trigger it in a loop once it has run. +echo "[golden] baking the controller-bootstrap PATH unit (starts the service on bootstrap-mount hot-plug — B1) …" +pct exec "$VMID" -- bash -c 'cat > /etc/systemd/system/felhom-controller-bootstrap.path < /etc/systemd/system/felhom-regen-hostkeys.service <