From cf807321e11751e2384486d76911239224a98b61 Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Thu, 9 Jul 2026 09:02:52 +0000 Subject: [PATCH] =?UTF-8?q?review(redfix):=20wake=20#45=20=E2=80=94=20186b?= =?UTF-8?q?0ba=20rewrite=20VERIFIED=20cold;=20A-redfix-2/3/4=20CLOSED;=20A?= =?UTF-8?q?-redfix-1=20=3D=20same=20live=20credential=20as=20B-redfix-8=20?= =?UTF-8?q?(sentinel=203fcea789=E2=80=A6,=20still=20unrotated)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- machine-docs/BACKLOG-redfix.md | 38 ++++++++++++++++++++++-- machine-docs/REVIEW-redfix.md | 54 ++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/machine-docs/BACKLOG-redfix.md b/machine-docs/BACKLOG-redfix.md index 329af26..afe744f 100644 --- a/machine-docs/BACKLOG-redfix.md +++ b/machine-docs/BACKLOG-redfix.md @@ -534,7 +534,7 @@ a sha alone is not durable evidence. Record the *content assertion* (file → ex or push a tag. The other three redfix fixes pinned exactly (`4ca7f418`, `a0f2db88`, `4987ba91`), as did cc-ci `redfix-m2-harness`@`07fc6d4a` — discourse drifted only because a later phase reused its branch. -### A-redfix-2 [adversary] — STATUS's "no code path redeploys it / recovery is manual" is REFUTED: the B-redfix-5 wedge **does** self-heal on the next unit activation, which makes it look intermittent +### A-redfix-2 [adversary] — **CLOSED 2026-07-09T08:59Z** (accepted at `f64d102`; false half superseded by A-redfix-4 at `e356698`) — STATUS's "no code path redeploys it / recovery is manual" is REFUTED: the B-redfix-5 wedge **does** self-heal on the next unit activation, which makes it look intermittent > **⚠ PARTIALLY WITHDRAWN by me at wake #44 (2026-07-09T08:5xZ) — see A-redfix-4.** > The *first* half (a code path redeploys it → the "recovery is manual" wording is wrong) **stands**. @@ -596,7 +596,7 @@ does restore live keycloak — but the foreign meta remains, so it re-wedges on is to remove the foreign `snapshot/`, not to redeploy."* The **precondition itself is unchanged and still correct**; only the mechanism/remediation sentences are wrong. -### A-redfix-3 [adversary] — STATUS's `main.go` "present in both clones ⇒ written outside git" evidence is void: `/srv/cc-ci` is a **symlink** to `/srv/cc-ci-orch`, so there is one file, not two +### A-redfix-3 [adversary] — **CLOSED 2026-07-09T08:59Z** (accepted + evidence retracted at `f64d102`; STATUS:28-29,564-572 re-read and correct) — STATUS's `main.go` "present in both clones ⇒ written outside git" evidence is void: `/srv/cc-ci` is a **symlink** to `/srv/cc-ci-orch`, so there is one file, not two Severity **INFO**. No VETO, no gate impact, no DoD impact. The *conclusion* (untracked, not from this phase, leave it alone) is fine; the supporting evidence is an artifact. @@ -627,7 +627,7 @@ on not deleting it: neither of us created it. --- -### A-redfix-4 [adversary] — the B-redfix-5 wedge has a **weekly autonomous re-trigger** (`nightly-sweep.timer`) and fails **silently**: post-arming, keycloak oscillates down-a-week / up-a-week with `nightly-sweep.service` reporting `Result=success` +### A-redfix-4 [adversary] — **CLOSED 2026-07-09T08:59Z** — all three asks applied at `e356698` and cold-re-verified by me at wake #45 (probes deleted; oscillation + silence recorded; precondition re-anchored to "never deploy `07fc6d4`"). The underlying *behaviour* remains open under **B-redfix-5**, which is deferred, not fixed. — the B-redfix-5 wedge has a **weekly autonomous re-trigger** (`nightly-sweep.timer`) and fails **silently**: post-arming, keycloak oscillates down-a-week / up-a-week with `nightly-sweep.service` reporting `Result=success` Severity **MED** (operator-facing; describes a *deferred* item's blast profile, **not** a DoD item). **No VETO. Does not reopen the phase.** M1 + M2 PASS stand. Merge target `b5f2b10` unchanged and still correct. @@ -722,3 +722,35 @@ means **the merge's own activation switch is itself a reconcile trigger**, along Remediation if ever armed is unchanged and still correct: **delete the foreign `snapshot/` from the slot**; do not redeploy keycloak (the sweep does that for you, and it is what masks the fault). + +--- + +### A-redfix-1 — ADDENDUM (wake #45, 2026-07-09T08:59Z): the embedded value is the **same live credential as B-redfix-8**, confirmed at value level; and rotation will **not** clean this file + +Still **OPEN**. Re-verified cold on cc-ci this wake, without printing the secret: + + ssh cc-ci 'stat -c "%a %U:%G" /etc/cc-ci/.git/config' # → 644 root:root + ssh cc-ci 'grep -oE "https://[^/@]+:[^/@]+@" /etc/cc-ci/.git/config \ + | sed -E "s#https://[^:]+:##; s#@$##" | tr -d "\n" | sha256sum | cut -c1-16' + +**EXPECTED / observed: `3fcea78925015fc9`** — byte-identical to the B-redfix-8 rotation sentinel +(`sha256(GITEA_PASSWORD)[:16]`, re-confirmed this wake from `/srv/cc-ci/.testenv` on the **orchestrator**). +So A-redfix-1 and B-redfix-8 are **two exposures of one still-unrotated, push-capable credential**, and the +sentinel matching proves it is **still not rotated**. (Extract-then-hash, never echo. `python3` is absent on +cc-ci — do not run the orchestrator's python probe over `ssh`; that is the `e3b0c44298fc1c14` empty-input tell.) + +**New, and operator-relevant: rotation does not fix this file, and may recreate the exposure.** +`/etc/cc-ci` is a **manual `git clone`**, not nix-generated — `nix/hosts/cc-ci-hetzner/configuration.nix:7` +documents `git clone --recursive https://git.autonomic.zone/recipe-maintainers/cc-ci.git /etc/cc-ci`. Nothing +regenerates `.git/config` on `nixos-rebuild switch`. Therefore: +- After rotating `GITEA_PASSWORD`, the **old** value persists verbatim in this 0644 file (inert, but it should + still be scrubbed — it is the value published at `14c7dee`). +- If the operator re-clones or re-embeds the **new** password in the remote URL, the 0644 exposure **returns**. + +**Recommendation (operator, alongside the B-redfix-8 rotation):** point the remote at a credential-less URL +(`https://git.autonomic.zone/recipe-maintainers/cc-ci.git`) and authenticate via a `credential.helper` / +token file with `0600`, or at minimum `chmod 0600 /etc/cc-ci/.git/config`. Do not carry userinfo in the URL. + +**Rotation blast radius is small** (checked, so this is not a reason to delay): `GITEA_PASSWORD` is consumed +only by `scripts/bootstrap-drone-oauth.sh` (a one-off bootstrap). `scripts/recipe-mirror-sync.sh` pushes with +an **OAuth token**, not the password, so the weekly sweep's mirror sync does **not** depend on it. diff --git a/machine-docs/REVIEW-redfix.md b/machine-docs/REVIEW-redfix.md index 02a1166..0ac005d 100644 --- a/machine-docs/REVIEW-redfix.md +++ b/machine-docs/REVIEW-redfix.md @@ -1433,3 +1433,57 @@ deferred/open. B-redfix-8 unchanged (OPEN/HIGH/operator-rotation-only; not re-pr Three asks of the Builder in A-redfix-4 — all STATUS text, no code, nothing reopens. Did not read JOURNAL-redfix.md before forming this verdict. + +--- + +## Wake #45 — 2026-07-09T09:02:52Z — Builder's A-redfix-4 rewrite (`e356698`) **VERIFIED**; A-redfix-2/3/4 CLOSED; A-redfix-1 re-confirmed live and linked to B-redfix-8 at value level. Still no VETO. + +Autonomous tick. `BUILDER-INBOX.md` consumed by the Builder (deleted); no `ADVERSARY-INBOX.md`; no gate +CLAIMED (STATUS:433 is the historical M2 claim, superseded by `## DONE` at :10). **M1 + M2 PASS stand, +`## DONE` stands, no VETO, merge target `b5f2b10` unchanged.** + +**All three A-redfix-4 asks applied — and I re-verified the rewrite rather than accepting it.** The lone +surviving `grep -i keycloak` string in STATUS (:152) is prose *warning against* the probe, not prescribing it; +the prescribed probe is now `git grep -n warm_reconcile -- runner/ nix/`, which is falsifiable and does find +both invokers. Deleted, not fixed — correct. + +**Every new claim in the rewrite checked cold; all hold:** +- `write_alert()` call sites `:493,500,503,539` ✓; `write_last_good()` `:478,484,491,527` ✓, all inside + `reconcile()` (`:448`–`:551`, `main()` at `:552`) ✓. +- "on `main` the same sites sit two lines earlier" ✓ exactly: `514→512`, `523→521`, `552→550`. +- `abra.undeploy` = single `_run(["app","undeploy",domain,"-n"], …, check=False)`, no `.env` handling ✓. +- fresh-deploy branch `:472 if not deployed` → `:479 return deployed-fresh:{target}`, no `warmsnap` ✓. +- `_assert_slot_not_foreign`: raises iff `meta and meta["domain"] != domain`; "a slot with no snapshot yet is + free to claim" ✓ (verbatim in the docstring). +- **"`python3` is absent there"** — I expected this to be the Builder's own unfalsifiable-probe slip. It is + **true**: `command -v python3` on cc-ci → not found. Claim survives. +- Trap not armed: slot holds `last_good` only, no `snapshot/meta.json`, no `/var/lib/ci-warm/canon-keycloak` ✓. + Live `https://warm-keycloak…/realms/master` → **200** ✓. +- Sound probe also surfaces a **third** invoker the Builder's EXPECTED text omits: `nix/modules/proxy.nix:27` + → `warm_reconcile.py traefik`. Not a defect — traefik is `stateful: False`, never snapshots, so blast radius + is unchanged. Noted, not filed. + +**I hardened my own wake-#44 evidence.** My mtime proof rests on "`write_last_good()` is reachable only from +`reconcile()`" — but I had verified that against `b5f2b10`, when the tree that actually ran on 2026-07-05 is +the **deployed** one. Re-checked repo-wide at `origin/main`: no caller outside `warm_reconcile.py`, all four +sites inside `reconcile()` (`:476,482,489,525`; `reconcile` `:446`, `main` `:550`). The proof holds **on the +correct tree**. Closing that gap is the same discipline that caught A-redfix-2. + +**A-redfix-2, A-redfix-3, A-redfix-4 → CLOSED** (I own closing them). A-redfix-4's *behaviour* remains open +under **B-redfix-5**, which stays deferred — the text is fixed, the wedge is not. + +**A-redfix-1: re-probed, STILL OPEN, and now pinned to B-redfix-8 at value level.** `/etc/cc-ci/.git/config` +is `644 root:root` and carries userinfo in the remote URL; extracting that password and hashing it (never +echoing it) yields **`3fcea78925015fc9`** — byte-identical to the B-redfix-8 rotation sentinel, re-confirmed +this wake from `/srv/cc-ci/.testenv` on the **orchestrator**. Two exposures, one credential, **still +unrotated**. New: `/etc/cc-ci` is a **manual `git clone`** (`nix/hosts/cc-ci-hetzner/configuration.nix:7`), +not nix-generated — so rotation neither scrubs this file nor regenerates it, and re-embedding the new password +recreates the exposure. Rotation blast radius is small (`GITEA_PASSWORD` is used only by +`scripts/bootstrap-drone-oauth.sh`; `recipe-mirror-sync.sh` pushes with an OAuth **token**), so there is no +operational reason to delay it. Addendum + recommendation filed under A-redfix-1. +**B-redfix-8 remains OPEN/HIGH/operator-rotation-only** — the sentinel check above is the sanctioned +non-republishing probe, and it says: not yet rotated. + +**Verdict: no VETO. `## DONE` stands. M1 + M2 PASS stand. Merge target `b5f2b10` unchanged.** + +Did not read JOURNAL-redfix.md before forming this verdict.