Files
felhom.eu/documentation/audits/restore-truth-2026-10-25/tools/keptprobe.py
T

103 lines
5.3 KiB
Python

#!/usr/bin/env python3
"""keptprobe.py — R-1271 live, on a throwaway drive-folder app this run installs (never a household's unit).
The measured case (catalog sweep 2026-10-24): a copy dated in the future beat the family's own copy. Here the
future-dated copy is FORGED on 9202 in a scratch place every box looks at — a second-drive copy of the app's own unit
under the system drive's backups/secondary/<app>/recovery-unit, its data time set to 2026-10-28T06:39:39Z (the
rehearsal box's clock), the only hand-made change. Then the household's order:
install, seed, „Mentés most", remove keeping data, install again → the question (expect: the OWN copy named, no
future flag); the own unit moved aside for a moment → the question again (expect: the forged copy offered, marked
future, with the sentence, not recommended); the own unit back → „A megőrzött adataimat használom" → the item back.
Then remove with data (the forged copy goes with the app's second-drive copies).
usage: SC=… SWEEP_EV=… TARGET=9202 DRIVE_ROOT=… python3 keptprobe.py <app>
"""
import json, os, sys, time
TOOLS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../catalog-sweep-2026-10-24/tools")
sys.path.insert(0, TOOLS)
import sweep as sw # noqa: E402
w, fxm = sw.w, sw.fxm
FUTURE = "2026-10-28T06:39:39Z"
def ask(app, sub):
os.environ.pop("KEPT", None)
c, d = w.ctl("POST", f"/api/stacks/{app}/deploy", {"values": dict(w.deploy_values(app, sub, dict(w.GENERATED.get(app) or {})))})
data = (d.get("data") or {}) if isinstance(d, dict) else {}
return c, {k: data.get(k) for k in ("code", "use_offered", "use_desc", "use_future", "use_warn", "use_off")}
def main(app):
d = os.path.join(sw.EV, "_keptprobe", app)
os.makedirs(d, exist_ok=True)
log = open(os.path.join(d, "walk.log"), "a")
def say(*a):
line = time.strftime("%H:%M:%SZ", time.gmtime()) + " " + " ".join(str(x) for x in a)
print(line, flush=True)
log.write(sw.scrub(line) + "\n")
log.flush()
w.say = say
fx = fxm.FIXTURES[app]
sub = getattr(fx, "sub", app)
rec = {"app": app}
forged = f"/mnt/sys_drive/felhom-data/backups/secondary/{app}/recovery-unit"
t_start = int(time.time())
unit = ""
w.login()
try:
rec["install"] = w.deploy(app, sub) and w.wait_app(sub, "/", tries=120, delay=5)
tok = fx.seed(w, sub, say)
rec["seed"] = bool(tok)
sw.backup_now(rec, say)
unit = sw.g(f"for p in /mnt/felhom-drives/*/backups/primary/{app} /mnt/felhom-drives/*/felhom-data/backups/primary/{app}; do [ -f $p/manifest.json ] && echo $p; done | head -1").strip()
rec["own_unit"] = unit
if not unit:
say(" no unit of the app on its drive — stop")
return
sw.g(f"rm -rf /mnt/sys_drive/felhom-data/backups/secondary/{app}; mkdir -p /mnt/sys_drive/felhom-data/backups/secondary/{app} && cp -a {unit} {forged} && "
f"sed -i -E 's/\"at\": \"[^\"]+\"/\"at\": \"{FUTURE}\"/' {forged}/manifest.json")
rec["forged_at"] = sw.g(f"grep -o '\"at\": \"[^\"]*\"' {forged}/manifest.json | head -2").strip()
say(f" forged a future-dated second-drive copy: {rec['forged_at']} (own unit: {unit})")
sw.remove(app, keep=True, say=say)
rec["q1_code"], rec["q1"] = ask(app, sub)
say(f" [question, own copy + future copy] {rec['q1_code']} {json.dumps(rec['q1'], ensure_ascii=False)[:400]}")
sw.g(f"mv {unit} {unit}.r1271-away")
rec["q2_code"], rec["q2"] = ask(app, sub)
say(f" [question, the future copy alone] {rec['q2_code']} {json.dumps(rec['q2'], ensure_ascii=False)[:500]}")
sw.g(f"mv {unit}.r1271-away {unit}")
os.environ["KEPT"] = "use"
w.DEPLOYED_THIS_RUN.discard(app)
rec["use_ok"] = w.deploy(app, sub, dict(w.GENERATED.get(app) or {}))
os.environ.pop("KEPT", None)
t0, last = time.time(), None
while time.time() - t0 < 1200:
time.sleep(5)
c, st = w.ctl("GET", "/api/backup/restore-status")
last = (st.get("data") or {}) if isinstance(st, dict) else {}
if not last.get("running") and time.time() - t0 > 10:
break
rec["load_status"] = json.dumps(last, ensure_ascii=False)[:600]
say(" load: " + rec["load_status"][:300])
w.wait_app(sub, "/", want=("200", "301", "302", "303", "307", "308", "401", "403"), tries=90, delay=5)
rec["item_after_load"] = bool(tok) and bool(fx.verify(w, sub, tok, say))
say(" item after use-my-kept-data: %s" % rec["item_after_load"])
finally:
os.environ.pop("KEPT", None)
if unit:
sw.g(f"[ -d {unit}.r1271-away ] && [ ! -e {unit} ] && mv {unit}.r1271-away {unit}")
rec["controller_lines"] = sw.scrub(sw.g(
f"docker logs --since {t_start} felhom-controller 2>&1 | grep -E '{app}' | grep -iE 'kept|USE MY|asking|future|restor' | cut -c1-300"))
if w.stack(app).get("deployed"):
sw.remove(app, keep=False, say=say)
rec["after_remove"] = sw.leftovers(app, sub)
rec["forged_left"] = sw.g(f"ls -d /mnt/sys_drive/felhom-data/backups/secondary/{app} 2>&1").strip()
json.dump(rec, open(os.path.join(d, "record.json"), "w"), ensure_ascii=False, indent=1)
if __name__ == "__main__":
main(sys.argv[1])