a29ee9dd33
gates / gates (push) Successful in 2m38s
Decision 150 (operator 13:25): sessions correct stale facts in instruction files themselves, naming each edit; never loosen a rule. Added to unprompted-work.md §5 (all copies) and PROMPT-TEMPLATE.md §9. CLAUDE.md gates paragraph (R-891), architecture pointer, docs/website rules, the doubled R-286 sentence in the workspace CLAUDE.md. Decision 149: vaultwarden's step proven on bench 9401 and box 9202 (evidence here). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
77 lines
4.4 KiB
Python
77 lines
4.4 KiB
Python
"""vwstep.py <to-ref> — R-890: vaultwarden's step on scratch 9202 (drill catalog), ONE process, through the product.
|
|
|
|
1 install vaultwarden fresh at the live pin (this run installs it — the admin seed refuses otherwise);
|
|
2 seed through the household's door, the invite through the admin page INSIDE the box
|
|
(FELHOM_BOX_ADMIN_SEED=1, upgrade_fixtures_box.box_admin_seed_allowed); read it back (C1);
|
|
3 a DRILL-only commit moves the image and adds a ladder entry; sync, rescan;
|
|
4 the product's guarded Update; the seed read back; box verdict JSON;
|
|
5 remove through the product.
|
|
Evidence: ../box/vaultwarden/step.txt + box-verdict-vaultwarden.json. The live entry is written ONLY by
|
|
`upgrade-test.py --write-ladder` from both verdicts."""
|
|
import json, os, re, subprocess, sys, time
|
|
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
|
import box_walk as w
|
|
import upgrade_fixtures_box as fixtures
|
|
|
|
APP, SUB, SVC = "vaultwarden", "vault", "vaultwarden"
|
|
to = sys.argv[1]
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
EVD = os.path.join(HERE, "..", "box", APP); os.makedirs(EVD, exist_ok=True)
|
|
log = open(f"{EVD}/step.txt", "a", buffering=1)
|
|
D = "/mnt/5_hdd/felhom.eu/drill/app-catalog-drill"
|
|
|
|
|
|
def say(*a):
|
|
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
|
|
|
|
|
fx = fixtures.FIXTURES[APP]
|
|
w.login()
|
|
if w.stack(APP).get("deployed"):
|
|
say("vaultwarden already installed on 9202 — removing it first (scratch box)")
|
|
w.remove(APP)
|
|
w.sync_rescan()
|
|
if not w.deploy(APP, SUB):
|
|
sys.exit(say("RESULT the install did not complete") or 1)
|
|
tok = fx.seed(w, SUB, say)
|
|
if tok is None or not fx.verify(w, SUB, tok, say):
|
|
say(f"RESULT C1 failed: {getattr(fx, 'tried', '')}")
|
|
w.remove(APP); sys.exit(1)
|
|
say("C1 seed reads back BEFORE: True")
|
|
before = (w.stack(APP).get("app_config") or {}).get("pinned_images")
|
|
say(f"before: pinned={before}")
|
|
subprocess.run(["git", "-C", D, "pull", "-q", "--rebase", "origin", "main"], check=True)
|
|
comp, fy = f"{D}/templates/{APP}/docker-compose.yml", f"{D}/templates/{APP}/.felhom.yml"
|
|
s = open(comp).read()
|
|
frm = re.search(r"^\s+image:\s*(\S+)", s, re.M).group(1)
|
|
open(comp, "w").write(s.replace("image: " + frm, "image: " + to, 1))
|
|
entry = {"from": {SVC: frm}, "to": {SVC: to}, "verdict": "proven", "tested_at": "DRILL", "harness_version": 5,
|
|
"evidence": "DRILL (box proof in progress)", "marks": {"files_may_change": False, "needs_person": None, "memory_tight": False}}
|
|
f = open(fy).read()
|
|
f = (f.rstrip("\n") + "\n - " + json.dumps(entry) + "\n") if "update_ladder:" in f else (f.rstrip("\n") + "\nupdate_ladder:\n - " + json.dumps(entry) + "\n")
|
|
open(fy, "w").write(f)
|
|
subprocess.run(["git", "-C", D, "commit", "-q", "-am", f"DRILL {APP}: {frm} -> {to} (box proof, R-890)"], check=True)
|
|
subprocess.run(["git", "-C", D, "push", "-q", "origin", "main"], check=True, capture_output=True)
|
|
say("drill:", subprocess.run(["git", "-C", D, "log", "--oneline", "-1"], capture_output=True, text=True).stdout.strip())
|
|
w.sync_rescan(APP, to)
|
|
say(f"badge before: {w.badges(APP)}")
|
|
since = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip()
|
|
res = w.press_update(APP, poll=1, cap_s=1800)
|
|
for p in res.get("phases", []):
|
|
log.write(f" phase +{p['t']}s {p['phase']} | err={p['error']}\n")
|
|
time.sleep(10)
|
|
read = fx.verify(w, SUB, tok, say)
|
|
lines = w.guest(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'update {APP}' | grep -v DEBUG | cut -c1-400")
|
|
log.write(lines + "\n")
|
|
st = w.stack(APP); after = (st.get("app_config") or {}).get("pinned_images")
|
|
verdict = {"app": APP, "venue": "box 9202 (drill catalog), the product's guarded Update; seeded through the admin invite inside the box (R-890)",
|
|
"from": before, "to": after,
|
|
"verdict": "proven" if (res.get("final_phase") == "done" and read and (after or {}).get(SVC) == to) else "failed",
|
|
"seed_read_before": True, "seed_read_after": read, "healthy_after": st.get("state") == "running",
|
|
"duration_s": res.get("duration_s"), "final_phase": res.get("final_phase"), "measured_at": since,
|
|
"evidence": "felhom.eu/documentation/audits/r890-instructions-2026-10-06/box/vaultwarden/step.txt"}
|
|
json.dump(verdict, open(f"{EVD}/box-verdict-{APP}.json", "w"), indent=2)
|
|
say(f"badge after: {w.badges(APP)}")
|
|
say(f"RESULT final_phase={res.get('final_phase')} after={after} seed_after={read} verdict={verdict['verdict']} ({res.get('duration_s')} s)")
|
|
say(f"remove -> {w.remove(APP)}")
|