# RUNBOOK GL-1 — execution record: publish agent 0.74.0 + bake/publish golden 0.103.0 (2026-07-07) **Class:** runbook execution (go-live item G1, partial). No code changes, no version bumps. Production touched read-only (felhom-pve: one `scp` out + `--version`/`readlink`; build server: normal kisfenyo work + drill-VM lifecycle). All root actions inside the disposable nested drill VM. No credential appears in this record; publish creds were sourced on the build server (`~/.gitea-token`, user `admin`) and the in-VM copy was shredded before poweroff. ## The four operator values (hub Day-0 manifest → Configs → Day-0 artifacts) ``` AGENT_VERSION=0.74.0 AGENT_SHA256=1ec3f58842edce1e9e32d022eaef15b7ff599c658c7a36bfe7833c708076af05 GOLDEN_VERSION=0.103.0 GOLDEN_SHA256=8481e8a14e2aa0abe3831cc40e5aea4c32f2017e7561c15dca8a674df6a6026e ``` ## Gate outcomes | Gate | Result | Evidence | |---|---|---| | 0a baselines | **PASS** | felhom-agent `ced60ddf` (v0.74.0), felhom-controller `59eb3bea` (v0.103.0), felhom.eu `02d63ed0`; published state pre-run: agent 0.63.0 = 200 / 0.74.0 = 404, golden 0.98.3 = 200 / 0.103.0 = 404 | | 0b drill VM | **PASS** | `~/drill/drill.qcow2` on 192.168.0.180 with internal snapshot `virgin` (2026-07-03) intact | | 0c controller image | **PASS** | `docker manifest inspect gitea.dooplex.hu/admin/felhom-controller:0.103.0` OK on the build server | | 0d headroom | **PASS** | 213 G free on 180 (golden ≈ 0.6 G); VM local-lvm 76 G thin, 0% used post-virgin | | 1a running binary | **PASS** | felhom-pve `readlink /proc/$(pidof felhom-agent)/exe` → `/usr/local/bin/felhom-agent`, `--version` → 0.74.0; selfupdate state dir EMPTY (no pending A/B marker) | | 1b agent publish | **PASS** | the LIVE bytes (sha identical across felhom-pve→CC→180 hops) published via `publish-agent.sh 0.74.0` from `main`@`ced60ddf`: pre-delete 404, PUT 201, round-trip GET sha match | | 2a drill VM ready | **PASS** | virgin-restored + booted (slirp `dhcpstart=10.0.2.30` + hostfwd 2222→10.0.2.15:22, per DRILL precedent); PVE 9.2.2 responsive; gitea HTTP/2 200 from inside; debian-13 template ABSENT on virgin (expected) → `pveam download` inside, checksum verified | | 2b bake + publish | **PASS** | `build-golden.sh` (main@`ced60ddf`, script v2.0.0) as root@pam in-VM, baking `felhom-controller:0.103.0`; transcript: `docker OK (overlay2; data-root /var/lib/docker)`, both `/var/lib/docker` + `/mnt/sys_drive` separate ext4 mounts, `including mount point` rootfs+mp0+mp1 (NO exclusions, no FATAL), archive 583MB, publish upload HTTP 201, `GOLDEN_VERSION=0.103.0` + sha printed. Token-leak grep over the transcript: 0 hits | | 3a agent fetch | **PASS** | **ANONYMOUS** GET → 200, sha256 == AGENT_SHA256 (from the build server; HEAD 200 from the CC machine off-LAN too) | | 3b golden fetch | **PASS** | **ANONYMOUS** GET → 200, 611 696 321 bytes, sha256 == GOLDEN_SHA256 (streamed to disk, hashed, deleted) | | 3c read-token finding | **see below** | | ## Gate 3c — read-credential finding (feeds G3) The specified reviewer read-only token (`8417…4140`) was **not locatable by CC** (not in the repos, not on the build server under any evident name). The gates were instead run with **no credential at all — and passed**: both generic packages are **anonymously world-readable** (deliberate posture; the agent's self-update and guest 9201's image pulls already rely on anon Gitea reads; integrity comes from the hub-manifest sha, not transport auth). Consequences: - A read-scoped token is trivially sufficient for artifact fetch — **rotating the customer `git.token` to read-only (or revoking its package-write) CANNOT break fresh installs' fetch path.** The G3 rotation is unblocked from this side. - Nuance: the installer (`resolve_git_creds`) **dies on an empty git token** even though the fetch itself would succeed anonymously — the credential is required by the script, not by Gitea. If the operator ever wants credential-less artifact fetch, that is a small host-install follow-up; until then customer configs still need a (read-scoped) token present. ## Drill-VM end state Build guest 9100 destroyed (`--purge`, all 3 LVs removed); in-VM cred file shredded; VM powered off; **qcow2 restored to `virgin`** (snapshot list verified) — the drill environment is exactly as found. Evidence retained on the build server: `~/drill/bake-0.103.0.log` (next to the prior `bake-A.log`). ## Deviations from the letter of the runbook - Gate 2a's template check was satisfied by downloading the template inside the VM (the virgin image never has it — same as the 0.98.3 bake) — anticipated by the runbook, noted as required. - Phase 3 ran anonymously instead of with the reviewer token (see Gate 3c) — a strictly *stronger* proof of fetchability. - The bake was launched as a transient systemd unit (`systemd-run --unit=golden-bake`) inside the VM instead of bare `nohup` (a plain ssh-backgrounded nohup did not survive session close). ## Follow-ups (operator) 1. **Hub Day-0 manifest bump** (Configs → Day-0 artifacts): enter the four values above. Until then fresh installs still fetch agent 0.63.0 + golden 0.98.3. 2. **Operator-key pin** (out of scope here): day-0 installs no operator pubkey, so agent self-update stays dormant on fresh boxes; (a) pin the real key on felhom-pve, (b) small host-install follow-up ships the pinned pubkey at day-0 — candidate to fold into GL-4. 3. **G3 git.token rotation**: unblocked per Gate 3c — issue read-scoped tokens (or rely on anon + keep a placeholder until the installer follow-up); also fixes demo-felhom's currently-EMPTY git credentials (found in GL-2; blocks any step-5 (re)install for that customer). 4. GL-6 supervised drill consumes the bumped manifest end-to-end (Scenario-D-style proof for 0.74.0/0.103.0 — deliberately NOT run here).