Commit Graph

1486 Commits

Author SHA1 Message Date
c541cb1474 networking: pin defaultGateway to eth0 (fixes no-default-route on 25.05+)
Some checks failed
continuous-integration/drone/push Build is failing
Since NixOS 25.05, scripted networking installs the default route from the
gateway interface's network-addresses-<iface>.service, matching the interface
via defaultGateway.interface or by subnet inclusion. Hetzner's off-subnet
point-to-point gateway (91.98.47.73/32 on eth0, gw 172.31.1.1) matched
neither with the bare-string form, so the 26.05 switch on 2026-08-03 left the
host with no default route and off the network (recovered via Hetzner rescue:
grubenv default back to the 24.11 generation).

With an explicit interface, the module installs both the gateway host route
and the default route from eth0's own unit:
  ip -4 route replace 172.31.1.1 proto static dev eth0
  ip -4 route replace default proto static dev eth0 via 172.31.1.1

Verified by nix eval of systemd.services.network-addresses-eth0.script.
2026-08-03 20:13:24 +00:00
4772e31296 flake: bump nixpkgs + sops-nix (2026-08-03)
Some checks failed
continuous-integration/drone/push Build is failing
nixpkgs: 50ab793 -> 531670d (nixos-26.05, was nixos-24.11 EOL)
sops-nix: 77c423a -> f140661 (master, buildGo125Module now builds on 26.05)

3-release channel jump (24.11 -> 25.05 -> 25.11 -> 26.05) to match the
orchestrator host and get CVE patches. 24.11 was EOL (2025-06-30).

Notable 26.05 changes reviewed: systemd Stage 1 boot (default, no config
change needed), dbus-broker default, bash nixos-rebuild removed (Python
rewrite mandatory; git present on host), MySQL 8.0 removed (not used as a
NixOS module). No system.rebuild/fileSystems/boot.initrd options in the
host config, so no config edits required.
2026-08-03 19:24:44 +00:00
25a583d00e decisions(secops): record gitea cred rotation + SSH auth migration + history scrub
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is passing
2026-07-10 17:37:16 +00:00
0d8adba8c3 fix(mirror-sync): push over SSH, not oauth2:token HTTP (B-redfix-9 root cause)
Some checks failed
continuous-integration/drone/push Build is failing
The token embedded in the recipe clone's gitea remote was copytree'd into the
world-readable per-run tree. SSH push keys the auth to ~/.ssh, so no secret is
written into any .git/config. API calls still use the token.
2026-07-10 17:27:17 +00:00
88ecbab4f3 chore(git): secrets submodule over SSH (git@:2222); git auth moved off HTTP to SSH keys 2026-07-10 17:22:19 +00:00
c89001ac0a chore(secrets): bump secrets submodule -> 2ce5f86 (bridge_gitea_token rotation)
Points the flake at the re-encrypted secrets.yaml carrying the fresh
bridge_gitea_token. Deploy with nixos-rebuild on cc-ci node.
2026-07-10 17:03:01 +00:00
9ea2fc6371 journal(redfix): Builder wake #66 — reboot onto closed phase, zero delta.
Terminal state re-verified cold. Corrected a near-miss from this wake: my first
`^## .*PASS` grep did not match the M1 verdict, which is a `###` heading at
REVIEW-redfix.md:22 — confirmed present by reading it, rather than reporting M1
PASS as missing. Both `## VETO` hits read in full: one CLEARED veto + its
clearance record, no standing veto. DONE @00:18Z, M1+M2 PASS, HEAD==origin/main,
no inbox. Untracked main.go re-checked by hash, identical to the file already
adjudicated (STATUS:710, A-redfix-3) — left untouched by design.

Remaining items (B-redfix-8, A-redfix-1) are operator-scope: history rewrite
(--force, forbidden) + credential rotation. Loop STOPPED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MWSJEPYEMx9LZhPwyQCmhP
2026-07-09 19:14:27 +00:00
ecd3239d0b journal(redfix): Builder wake #65 — reboot onto closed phase, zero delta.
HEAD==origin/main==89af75b is my own wake-#64 journal: neither the Adversary nor the tree has moved
since I last stopped, so there was no handoff to answer. Terminal state re-verified cold anyway:
DONE @00:18Z, M1+M2 PASS, both '## VETO' headings read individually and confirmed historical (:553
annotated CLEARED, :649 is the clearance record) rather than inferred from a grep count. No inbox.
Untracked main.go left in place per the standing adjudication at STATUS:710 / A-redfix-3.

Declined to re-run M1/M2 on an unmoved tree — it would mint a fresh timestamp without new evidence.
Remaining items are operator-scope: B-redfix-8 (history rewrite, --force forbidden) and A-redfix-1
(credential rotation). Loop STOPPED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015yZh7A6Zcac5LQ3tqqtb9W
2026-07-09 14:43:46 +00:00
89af75b7bf journal(redfix): Builder wake #64 — no-op; the moved ref was the Adversary's own chore( re-confirmation, not a handoff (read the diff, didn't infer). Terminal state re-verified cold: DONE @00:18Z, M1+M2 PASS, both '## VETO' headings confirmed historical by annotation, HEAD==origin/main @6f733dc, no inbox, redfix-m2-harness unmerged. Untracked main.go is NOT a stray to clean up — already adjudicated at STATUS:710 + A-redfix-3 (the 'both clones' evidence was void: /srv/cc-ci is a symlink, one inode). Left in place: committing would launder unexplained state, deleting would destroy operator evidence. Remaining items (B-redfix-8, A-redfix-1) are operator-scope: history rewrite + rotation. Loop STOPPED. 2026-07-09 12:06:00 +00:00
6f733dcbac chore(redfix): Adversary wake #63 — no-op re-confirmation on a closed phase; no new verdict.
Terminal state re-verified cold: DONE @00:18Z, M1+M2 PASS stand, no standing VETO (both '## VETO' hits
read, not counted: one CLEARED + its clearance record), all findings CLOSED, HEAD==origin/main, no inbox.
Live host re-probed: /etc/cc-ci HEAD==d11f8f5 unmoved since #54, 07fc6d4 not an ancestor, object present
-> B-redfix-5 negative is real, not vacuous. Declined to re-run M1/M2 on an unmoved tree.

Prefix is 'chore(' not 'review(' ON PURPOSE: no verdict landed this wake. The Builder's #63 journal shows
my last review( commit fired a watchdog handoff ping that resolved to a no-op; a third false ping would
degrade 'review(' as a signal. Loop STOPPED.
2026-07-09 12:04:34 +00:00
919a1bdfa1 journal(redfix): Builder wake #63 — watchdog ping resolved to a no-op (f5ea13a was the Adversary's own re-confirmation, not a new finding). Terminal state re-verified cold: DONE @00:18Z, M1+M2 PASS intact, both '## VETO' headings confirmed historical by annotation (not inferred from grep count), HEAD==origin/main, no inbox, redfix-m2-harness still unmerged per the 'nothing merged' DoD clause. No unblocked Builder work: B-redfix-8 needs a history rewrite + rotation, both operator-scope and --force-forbidden. Declined to re-run M1/M2 on an unmoved tree. Loop STOPPED. 2026-07-09 11:58:50 +00:00
f5ea13a04d review(redfix): wake #62 — reboot onto closed phase; terminal state re-verified cold. The grep -c VETO==2 is one CLEARED veto + its clearance record, not two standing vetoes (checked, not assumed). DONE stands, M1+M2 PASS stand, HEAD==origin/main @5b69b34, no inbox, no open findings. Live host re-probed: /etc/cc-ci HEAD==d11f8f5 unmoved since #54, 07fc6d4 not an ancestor, object present → B-redfix-5 negative is real not vacuous. Declined to re-run M1/M2 on an unmoved tree. Loop STOPPED. 2026-07-09 11:57:48 +00:00
5b69b3414d review(redfix): wake #61 — reboot onto closed phase; terminal state re-verified cold (DONE, no standing VETO, HEAD==origin/main @437daef, redfix-m2-harness still unmerged, no inbox). Live host re-probed: /etc/cc-ci HEAD==d11f8f5 unmoved since #54, 07fc6d4 still not an ancestor, and the object IS present — so the B-redfix-5 'never deploy 07fc6d4' negative is real, not vacuous. Declined to re-run M1/M2 on an unmoved tree. Loop STOPPED. 2026-07-09 11:51:25 +00:00
437daef901 review(redfix): wake #60 — reboot onto closed phase; terminal state re-verified cold (DONE, no standing VETO, HEAD==origin/main @65c21c6, nothing merged, no inbox). Additionally re-probed the LIVE host: /etc/cc-ci HEAD==d11f8f5 (unmoved since #54) and 07fc6d4 still not an ancestor — the B-redfix-5 "never deploy 07fc6d4" precondition holds despite the weekly nightly-sweep re-trigger. Declined to re-run M1/M2 on an unmoved tree. Loop STOPPED.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Eba9An8VyzE8Cpib74wghT
2026-07-09 11:45:08 +00:00
65c21c6c2e journal(redfix): Builder wake #59 — reboot onto closed phase; terminal state re-verified cold (DONE, no standing VETO, HEAD==origin/main, nothing merged, no inbox). No new work: remaining items are operator-scope. Loop STOPPED. 2026-07-09 11:33:48 +00:00
ddaccd0afc review(redfix): wake #59 — reboot onto closed phase; terminal state re-verified cold (DONE, no standing VETO, HEAD==origin/main @71c9b90, nothing merged, no inbox). Declined to re-run M1/M2 on an unmoved tree — idle-filler, not pressure. Loop STOPPED. 2026-07-09 11:20:02 +00:00
71c9b906b5 journal(redfix): wake #58b — Adversary CONFIRMED both findings; chased the 3061-vs-3099 discrepancy to hardlinked local clones + unreachable objects; 'record the invariant, not the measurement'; loop STOPPED
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 11:04:25 +00:00
ab4be1b419 fix(redfix): B-redfix-8 reproduction quoted a brittle blob total (3099); the invariant is password=2 / token=0
Adversary (a22c384) confirmed both findings but counted 3061 blobs vs my 3099. Root-caused:
(a) later commits add blobs (host now 3104); (b) --batch-all-objects counts 49 unreachable
objects rev-list omits (reachable-only = 3026); (c) 'git clone /local/path' hardlinks the whole
object store, so local clones inherit unreachable objects while remote clones do not -- hence
the Adversary's lower, and for a mirror question more apt, number.

All four scans agree on password=2 and token=0. STATUS now asserts those invariants and a
'wc -l > 100' sanity floor instead of an exact total, so the documented repro cannot misfire.

Operator-scope, no gate impact, no VETO; DONE stands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 11:03:53 +00:00
a22c384eeb review(redfix): wake #58 — adjudicate Builder mirror-blob correction cold. CONFIRMED independently: token 0/3061 blobs (filesystem-only, not on mirror); password exactly 2 blobs (fd21fcb8@2ad38f5 AND bcc31b55@e64d8e7), both mirror-served ancestors, HEAD clean. Builder's prior 'only 2ad38f5' understated — correct count is 2. Accepted the fair catch that my wake-#57 'both creds' sentence overreached (untested mirror surface). Asymmetry real: pw=mirror+FS, token=FS-only. No gate impact, no VETO; DONE stands. Consumed inbox. 2026-07-09 11:01:54 +00:00
21d31664b6 journal(redfix): wake #58 — why I probed the Adversary's PASS instead of acknowledging it; awk-absent vacuous-zero near-miss recorded
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 10:59:25 +00:00
f59494fbb3 inbox(redfix): wake #58 — your #57 probe skipped the public mirror; I closed it. Token NOT in history (0/3099, your PASS extends). But my own STATUS understated B-redfix-8: password is served by TWO published commits (2ad38f5 + e64d8e7), not one. Probe hygiene: no awk here; positive control must return 2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 10:58:59 +00:00
fb92c7b992 fix(redfix): B-redfix-8 exposure UNDERSTATED — password is served by TWO published commits (2ad38f5 + e64d8e7), not one; oauth2 token is NOT in git history (0/3099 blobs)
Closes the gap in Adversary wake #57's break-it probe, which covered dashboard/reports/Drone
logs but not the public git mirror -- the surface B-redfix-8 is about.

- password sha16 3fcea78925015fc9 -> 2 blobs, 2 commits, both ancestors of origin/main.
  Scrubbing 2ad38f5 alone would leave e64d8e7 serving the live credential. STATUS corrected.
- oauth2 token sha16 9c44a1aea2ecb389 -> 0/3099 blobs. Filesystem-only exposure.
- Probe hygiene: awk is absent here; awk-based blob lists give a vacuous 0. Positive
  control (password must return 2) is now mandatory and documented.

Operator-scope, no gate impact, no VETO; DONE stands.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 10:58:13 +00:00
f35332efbc review(redfix): wake #57 break-it probe — oauth2 token does NOT leak to any published surface (dashboard/reports/console logs all clean; Drone log API 401). 'No secrets published' invariant now verified for BOTH exposed creds, not just the password. No VETO; DONE stands. 2026-07-09 10:53:45 +00:00
7d7761f069 journal(redfix): wake #57 — Builder reboot on closed phase; terminal state re-verified cold (DONE, no VETO, merge target b5f2b10 unmoved, nothing merged); loop STOPPED
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018XE43k4DaeMXHMK51wBUu2
2026-07-09 10:51:48 +00:00
049a287301 journal(redfix): wake #56 — Adversary close-out, full agreement; 78-vs-68 reconciled as scope diff (68 /var/lib + 10 outside); no action
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9GyBPF1EgTTh6277Xjj7k
2026-07-09 10:45:26 +00:00
6049caec37 review(redfix): wake #56 — adjudicate Builder concession cold. Both my wake-#55 corrections CONFIRMED accepted; token liveness VERIFIED first-hand (GET /api/v1/user -> 200, autonomic-bot id=64, live 40-char oauth2 token on git.autonomic.zone). Census: token=117 confirmed exact, password=68 (Builder 78; 10-file gap = regex-form diff, immaterial). Operator-scope, no gate impact, no VETO; DONE stands. Consumed inbox. 2026-07-09 10:43:33 +00:00
28529e7508 fix(redfix): STATUS/BACKLOG — TWO exposed live credentials, sweep regenerates them WEEKLY (both corrections conceded to Adversary)
Adversary wake #55 conceded my insteadOf falsification but corrected me twice; verified both first-hand:

1. "Production CI does not regenerate / manual-* = hand-run" WRONG. run_id()=manual-<pid> for any non-Drone
   run (run_recipe_ci.py:318-319); nightly-sweep runs run_recipe_ci.py outside Drone with CCCI_SKIP_FETCH=1
   (nightly_sweep.py:88). Sweep regenerates the exposed copies WEEKLY (freshest 07-05 03:37-59 = sweep fire).

2. Census missed a 2nd credential (grep keyed on autonomic-bot: cannot see oauth2:). Full per-file census:
   78 files carry the password, 117 a live oauth2 token, 62 both, 133 distinct under /var/lib. Token is LIVE
   + PUSH-capable (api/v1/user->200 autonomic-bot/64) and is what recipe-mirror-sync.sh:39 pushes with —
   falsifies my own B-redfix-8 "small blast radius" note.

STATUS steps 3-4 rewritten (two creds, weekly regen, combined remedy + chmod 0750); B-redfix-8/9 corrected.
DONE stands; no VETO; no DoD item touched; rotation of BOTH secrets remains operator-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9GyBPF1EgTTh6277Xjj7k
2026-07-09 10:38:09 +00:00
ad1abcb792 review(redfix): wake #55 — adjudicate Builder rebuttal cold. CONCEDE my insteadOf root cause is FALSIFIED (reproduced: insteadOf stores original URL, injects no userinfo); real generator is the sweep's CCCI_SKIP_FETCH copytree of /root/.abra canonical clones. CORRECT Builder: manual-* are NOT hand-runs — the autonomous nightly sweep runs run_recipe_ci.py outside Drone (run_id()=manual), regenerating copies WEEKLY (freshest dated to 07-05 sweep fire). NEW: a 2nd credential (oauth2/9c44a1) is exposed in 55 copies — Builder census of 78 missed it; 123 world-readable cred configs in /var/lib total. Operator-scope, no gate impact, no VETO; DONE stands. Consumed inbox. 2026-07-09 10:31:25 +00:00
94fb219967 fix(redfix): correct STATUS — A-redfix-1 is 78 copies not 1; insteadOf root cause falsified; sweep runs deployed /etc/cc-ci
Adversary wake #53/#54 reaffirm DONE + no VETO (no gate impact), but both correct STATUS text (Builder-owned):

1. A-redfix-1 "sole copy" withdrawn: 78 world-readable cred-bearing .git/config, sentinel 3fcea78925015fc9.
   Exposure confirmed; Adversary's /root/.gitconfig insteadOf root cause FALSIFIED three ways (clone does not
   persist insteadOf rewrites — tested, git 2.47.2; /etc/cc-ci config predates .gitconfig by 2wk; live
   fetch_recipe uses a non-persisted http.extraHeader token since 9b33fdf, so 0/215 numeric runs carry it).
   Real generator: CCCI_SKIP_FETCH copytree of credentialed /root/.abra/recipes (0700) into 0755 run tree.
   STATUS steps 3-4 rewritten; filed B-redfix-9 (deferred). Falsification sent via ADVERSARY-INBOX.md.

2. Sweep mechanism: runs deployed /etc/cc-ci (main @ d11f8f5), not origin/main. Verified first-hand.

DONE stands; no VETO; no DoD item touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9GyBPF1EgTTh6277Xjj7k
2026-07-09 10:25:52 +00:00
4d40af102f review(redfix): wake #54 — cold re-verify on closed phase; DONE + no-VETO reaffirmed; 'never deploy 07fc6d4' invariant HOLDS on the live node (07fc6d4 not an ancestor of deployed HEAD d11f8f5; keycloak WARM_CANONICAL=False is a real assignment). STATUS mechanism CORRECTED: sweep runs deployed /etc/cc-ci, not origin/main — guarantee is a property of what is deployed. No gate impact. 2026-07-09 10:23:29 +00:00
493c5a81ab review(redfix): wake #53 — cold re-verify on closed phase; DONE + no-VETO reaffirmed; A-redfix-1 'sole copy' FALSIFIED (78 world-readable cred copies, root-caused to /root/.gitconfig insteadOf; dashboard invariant HOLDS, operator-scope widened, no gate impact)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0123qkYW7yhbqntjcjVvTUQ2
2026-07-09 10:16:03 +00:00
9d34367fa2 journal(redfix): wake #53 — Builder reboot on closed phase; terminal state re-verified; loop stopped
No standing VETO (2x '## VETO' headings are historical: one annotated CLEARED, one is the clearing
record). STATUS:481 CLAIMED is the superseded historical M2 claim. No action available; loop stopped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y9GyBPF1EgTTh6277Xjj7k
2026-07-09 10:15:16 +00:00
bb70963f07 journal(redfix): wake #52 — reboot on closed phase; terminal state re-verified; loop stopped (no standing VETO; 2x '## VETO' headings are historical)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FFBXjE2djJjKa1y4WU9Bxw
2026-07-09 10:02:47 +00:00
dabf348129 journal(redfix): wake #51 — Builder reboot on closed phase; terminal state re-verified; no action
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CHXAUm8j2HKunKf6Q5r9YQ
2026-07-09 09:56:37 +00:00
142ddd6bf1 journal(redfix): wake #50 — Builder reboot on closed phase; terminal state re-verified cold; no action
Stop condition re-checked from a cold read: STATUS ## DONE, M1+M2 fresh PASS, no standing
VETO (line 553 header is annotated CLEARED), no inbox either direction, Adversary loop
closed out at #49. Loop stays stopped; no DoD item re-run.

Sentinel re-probed this wake: GITEA_PASSWORD still hashes to 3fcea78925015fc9 (unrotated).
A-redfix-1 / B-redfix-8 remain OPEN/HIGH, operator-rotation-only, gating nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TRRkTGdWKWoxddF6QXhWfd
2026-07-09 09:50:12 +00:00
9bc04e9790 journal(redfix): wake #49 — Adversary close-out acknowledged; no VETO, no Builder action; both loops closed 2026-07-09 09:43:18 +00:00
473ad87fb1 review(redfix): wake #49 — ADVERSARY LOOP CLOSE-OUT; Builder terminated, DoD complete, no VETO, DONE stands (A-redfix-1/B-redfix-8 operator-only) 2026-07-09 09:42:34 +00:00
3b83b693a6 journal(redfix): wake #48 — loop terminated; sentinel re-probed and still unrotated (operator-only) 2026-07-09 09:36:09 +00:00
a7cc03bbc1 journal(redfix): wake #47 — loop termination check; sentinel still unrotated; no Builder-actionable work
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsFDnuxajtYb5UC1Hx1P6U
2026-07-09 09:22:50 +00:00
3ec56d878e status(redfix): record Adversary wake-#46 cold-verification of the strip remedy; consume BUILDER-INBOX
Adversary confirmed all three claims and failed to refute "strip userinfo is safe" three ways:
no push through /etc/cc-ci origin; secrets submodule anonymously fetchable so submodule update
survives; nothing auto-pulls the checkout (/root/.git-credentials inert, no helper wired).

Folded those three into STATUS step 3 so the operator sees why the command is safe. The submodule
angle was an inference on my part, not a probe -- the Adversary actually tested it. Recorded in
JOURNAL.

Incidental (not a finding): cc-ci-secrets.git is public but SOPS-encrypted ciphertext.

STATUS/JOURNAL text only. No code. ## DONE stands; M1+M2 PASS stand; no gate reopens.
2026-07-09 09:09:29 +00:00
1dcb99911f review(redfix): wake #46 — Builder's 'strip userinfo is safe' CONFIRMED (refutation failed 3 ways); all 3 claims cold-verified; consumed inbox 2026-07-09 09:08:31 +00:00
1351981730 inbox(redfix): heads-up — A-redfix-1 folded into B-redfix-8 remedy; please cold-check the 'strip userinfo is safe' claim 2026-07-09 09:05:44 +00:00
658f9c40b6 status(redfix): fold A-redfix-1 into the B-redfix-8 operator remedy — one credential, two exposures
Adversary wake #45 established A-redfix-1 and B-redfix-8 are the same credential. Re-derived
every claim first-hand before writing it (the A-redfix-2 lesson), incl. value identity:
.git/config userinfo and .testenv GITEA_PASSWORD both hash to 3fcea78925015fc9; control
sha256("")=e3b0c44298fc1c14 rules out the empty-input probe artifact.

Rotation does NOT scrub /etc/cc-ci/.git/config (644 root:root, manual clone per
configuration.nix:7, not nix-generated). Remedy is now a 3-step operator procedure that
strips the userinfo rather than re-embedding the rotated password (re-embedding would
recreate the exposure). Verified the strip is safe: anonymous ls-remote succeeds rc=0.

Blast radius recorded: GITEA_PASSWORD is consumed only by bootstrap-drone-oauth.sh;
recipe-mirror-sync.sh uses an OAuth token. No reason to delay rotation.

STATUS text only. No code. ## DONE stands; M1+M2 PASS stand; no gate reopens.
2026-07-09 09:05:26 +00:00
cf807321e1 review(redfix): wake #45186b0ba rewrite VERIFIED cold; A-redfix-2/3/4 CLOSED; A-redfix-1 = same live credential as B-redfix-8 (sentinel 3fcea789…, still unrotated) 2026-07-09 09:02:52 +00:00
186b0ba46b status(redfix): accept A-redfix-4 — weekly nightly-sweep.timer re-triggers reconcile; wedge is silent + recurring
Independently re-verified every leg against the node before editing (I adopted
A-redfix-2's probes wholesale at 8276ecd and inherited its error; not repeating that).

- Delete both 'no re-trigger' probes: they grep the app name, but the timer is
  named nightly-sweep, so they return empty while a timer drives it weekly.
  Sound probe greps the callee: git grep warm_reconcile -- runner/ nix/
- Replace 'recovery is manual' / 'heals on reboot' with the weekly DOWN/UP
  oscillation, and record that it is SILENT (roll_warm_infra discards the rc;
  the raise is upstream of every write_alert).
- Re-anchor the merge precondition: 'slot clean at merge time' -> 'never deploy
  07fc6d4'. A git merge executes nothing; b5f2b10 ships enrollment + fix together,
  so the precondition is self-maintaining.
- Line refs pinned to b5f2b10 coordinates (were main's, two lines off).
- BACKLOG B-redfix-5: severity corrected, remedy sketch extended to rc propagation.

Not armed and not self-arming: origin/main (the tree the sweep runs) has
WARM_CANONICAL = False. Nothing reopens; DONE stands, no VETO, b5f2b10 unchanged.
Inbox consumed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TkHo7RixQswYvvNnEcNaqW
2026-07-09 08:52:44 +00:00
85b068e395 review(redfix): wake #44 — I REFUTE my own A-redfix-2; nightly-sweep.timer is a weekly re-trigger, wedge is silent + recurring (A-redfix-4) 2026-07-09 08:47:34 +00:00
07508a8d4d journal(redfix): loop close-out — why DONE stands and why B-redfix-8 / B-redfix-5 are not Builder-actionable
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TkHo7RixQswYvvNnEcNaqW
2026-07-09 08:44:02 +00:00
8630e70459 status(redfix): account for A-redfix-1/2/3 in the DONE block — none blocking, A-2/A-3 accepted
The DONE block listed F-redfix-1/2/3/4 as CLOSED but never mentioned the three
A-redfix-* findings, leaving them dangling for an operator reading only DONE.
All three are non-VETO and outside the DoD (Adversary wake #43, 1057657).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TkHo7RixQswYvvNnEcNaqW
2026-07-09 08:43:37 +00:00
8276ecdfe0 status(redfix): accept A-redfix-2 + A-redfix-3 — correct the self-heal mechanism and retract the "both clones" evidence
Both claims re-derived independently before editing; both of mine were wrong.

A-redfix-2: "no code path redeploys it" is FALSE. abra.undeploy() leaves the app
.env, so the next reconcile() takes the fresh-deploy branch (:471-479), which
redeploys and never calls warmsnap. Self-healing is blocked by the absence of a
re-trigger (warm-keycloak.service: Type=oneshot, RemainAfterExit=true, no timer,
no Restart=), so it heals on reboot/nixos-rebuild and RE-WEDGES on the next due
upgrade while the foreign snapshot/meta.json remains. Operator remediation is to
DELETE the foreign snapshot/, not to redeploy keycloak. Failure presents as an
intermittent flake, not a permanent outage.

A-redfix-3: /srv/cc-ci is a symlink to /srv/cc-ci-orch, so the two main.go paths
are the same inode (3254604, links=1). The "present in both clones" premise is
void and proves nothing about the file's origin (still unexplained; inert).

Docs-only. No DoD item, gate, or verdict affected: ## DONE stands, M1 + M2 PASS
stand, merge target b5f2b10 unchanged, no VETO. The B-redfix-5 merge precondition
is unchanged and still correct.
2026-07-09 08:35:51 +00:00
10576574c5 review(redfix): wake #43 — A-redfix-2 REFUTES "no code path redeploys it"; A-redfix-3 voids the "both clones" evidence
Probed the two operator-facing claims in the Builder's new commits (cbeceea, d5dc547). No inbox, no gate.

A-redfix-2 (LOW-MED) — "The wedge does not self-heal ... no code path redeploys it. Recovery is manual."
Conclusion right, mechanism wrong. abra.undeploy() does not remove the app .env, so the next reconcile()
sees current_version resolvable + is_deployed False and takes the fresh-deploy branch
(warm_reconcile.py:471-479), which redeploys and NEVER calls warmsnap -- the guard is unreachable there.
What actually blocks self-healing is the lack of a re-trigger: warm-keycloak.service is Type=oneshot with
no timer and no Restart=. So it heals on the next reboot / nixos-rebuild switch, then RE-WEDGES on the next
due upgrade because the foreign snapshot/meta.json is still in the slot. The failure therefore presents as
an intermittent flake, and the correct remediation is removing the foreign snapshot/, not redeploying
keycloak. Asked the Builder to correct two sentences; the precondition itself is unchanged and still right.

A-redfix-3 (INFO) — "main.go present in both clones => written outside git". Evidence void: /srv/cc-ci is a
SYMLINK to /srv/cc-ci-orch, so both paths are the same inode (2049:3254604, links=1). One file, one clone.
Risk bounded: 281-byte hello-world net/http listener, no go.mod, go not installed, nothing on :8080, in no
commit, unreferenced, inert. Concur with leaving it in place.

No VETO. DONE stands, M1+M2 PASS stand, merge target b5f2b10 unchanged. B-redfix-8 unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SoraVF2hkEMExHswFX1g4M
2026-07-09 08:32:49 +00:00