Files
felhom.eu/documentation/audits/night-2026-09-26/tools/e5.py
T

89 lines
4.9 KiB
Python

"""e5.py <step> — Part E's live proof on 9202 (controller 0.274.0-rc1, drill catalog), one step per call.
Every act through the product's own endpoints (the ones the pages call). Evidence: E/E5-<step>.txt."""
import json, sys, time, re
import walk as w, fixtures
step = sys.argv[1]
OUT = open(f"{w.EV}/E/E5-{step}.txt", "w", buffering=1)
def say(*a):
w.say(*a); OUT.write(" ".join(map(str, a)) + "\n")
HDD = "/mnt/felhom-drives/scratch_hdd"
TOK = w.SC + "/seed-tokens.json"
w.login()
def kept_page(lang=""):
h = w.page("/kept-data" + ("?lang=en" if lang else ""))
t = re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", h))
return t
def deploy(choice=None, lang=""):
vals = w.deploy_values("nextcloud", "c-nc"); vals["HDD_PATH"] = HDD
body = {"values": vals}
if choice:
body["kept_data"] = choice
return w.ctl("POST", "/api/stacks/nextcloud/deploy" + ("?lang=en" if lang else ""), body)
def wait_deployed(limit=600):
t0 = time.time()
while time.time() - t0 < limit:
st = w.stack("nextcloud")
if st.get("deployed") and (st.get("app_config") or {}).get("pinned_images") and st.get("state") in ("running", "unhealthy", "degraded"):
return round(time.time() - t0, 1), st.get("state")
time.sleep(5)
return None, w.stack("nextcloud").get("state")
def g(cmd):
return w.guest(cmd)
say(f"# E5 {step} — {time.strftime('%FT%T%z')}; controller {g('cat /etc/felhom-controller-image').strip()}")
if step == "1-list":
say("drive:", g(f"ls -la {HDD}; ls -la {HDD}/appdata {HDD}/kept 2>&1; du -sh {HDD}/appdata/nextcloud 2>&1"))
for lang in ("", "en"):
t = kept_page(lang)
i = t.find("extcloud")
say(f"GET /kept-data{'?lang=en' if lang else ''}: ...{t[max(0,i-300):i+500]}...")
elif step == "2-ask":
for lang in ("", "en"):
code, d = deploy(None, lang)
say(f"deploy, no choice, lang={lang or 'hu'} -> {code}")
say(json.dumps(d, ensure_ascii=False, indent=1)[:1600])
say("still not installed:", w.stack("nextcloud").get("deployed"), g(f"ls {HDD}/appdata"))
elif step == "3-fresh":
code, d = deploy("fresh")
say(f"deploy kept_data=fresh -> {code} {str(d)[:200]}")
say("deployed after", wait_deployed())
say("drive now:", g(f"ls -la {HDD}/appdata {HDD}/appdata/nextcloud 2>&1 | head -20; find {HDD}/kept -maxdepth 3 | head; du -sh {HDD}/kept/nextcloud/* 2>&1"))
toks = json.load(open(TOK)); toks["nextcloud"] = fixtures.FIXTURES["nextcloud"].seed(w, "c-nc", say)
json.dump(toks, open(TOK, "w"), default=str)
say("seeded:", toks["nextcloud"] is not None)
t = kept_page(); i = t.find("extcloud"); say("kept page:", t[max(0, i-200):i+600])
elif step == "4-remove-keep":
code, d = w.ctl("POST", "/api/stacks/nextcloud/stop"); say("stop", code)
time.sleep(15)
code, d = w.ctl("POST", "/api/stacks/nextcloud/remove", {"remove_hdd_data": False, "remove_backups": False})
say(f"remove keep data + backups -> {code} {str(d)[:200]}")
time.sleep(8)
say("after:", w.stack("nextcloud").get("deployed"), g(f"ls {HDD}/appdata; ls -la --time-style=+%FT%T {HDD}/backups/primary/nextcloud {HDD}/backups/primary/nextcloud/db-dumps 2>&1 | tail -8"))
elif step == "5-use":
code, d = deploy(None)
say(f"ask first -> {code} use_offered={(d.get('data') or {}).get('use_offered')} use_desc={(d.get('data') or {}).get('use_desc')}")
since = g("date -u +%Y-%m-%dT%H:%M:%SZ").strip()
code, d = deploy("use")
say(f"deploy kept_data=use -> {code} {str(d)[:200]}")
say("deployed after", wait_deployed(1200))
for i in range(60):
if "after_load" in g(f"docker logs --since {since} felhom-controller 2>&1 | grep -c after_load") or i > 58:
break
time.sleep(5)
time.sleep(20)
say("controller lines:\n" + g(f"docker logs --since {since} felhom-controller 2>&1 | grep -iE 'kept|after_load|restore|unit|Restor' | grep -v DEBUG | cut -c1-300 | head -40"))
toks = json.load(open(TOK))
say("seed (the account) reads back:", fixtures.FIXTURES["nextcloud"].verify(w, "c-nc", toks["nextcloud"], say))
elif step == "6-fresh-again":
code, d = w.ctl("POST", "/api/stacks/nextcloud/stop"); time.sleep(15)
code, d = w.ctl("POST", "/api/stacks/nextcloud/remove", {"remove_hdd_data": False, "remove_backups": False})
say(f"remove keep data + backups -> {code}")
time.sleep(8)
code, d = deploy("fresh"); say(f"deploy fresh -> {code} {str(d)[:160]}"); say("deployed after", wait_deployed())
say("kept now:", g(f"find {HDD}/kept -maxdepth 3 | head -20; du -sh {HDD}/kept/nextcloud/* 2>&1"))
code, d = w.ctl("POST", "/api/stacks/nextcloud/stop"); time.sleep(15)
code, d = w.ctl("POST", "/api/stacks/nextcloud/remove", {"remove_hdd_data": False, "remove_backups": True})
say(f"remove the fresh install (keep data, delete backups) -> {code} {str(d)[:160]}")
time.sleep(8)
for lang in ("", "en"):
t = kept_page(lang); i = t.find("extcloud"); say(f"kept page {lang or 'hu'}:", t[max(0, i-200):i+1200])