"""r717live.py — R-717 live proof on scratch 9202 (test controller 0.301.0, drill catalog with wishlist's after_setup). 1 wishlist installed fresh; the household's first account (the fixture, through the setup gate); 2 the household opens the app (POST /apps//setup-gate/open) → after_setup's close command runs; the DB value read (enableSignup=false) + the controller's own lines; 3 a STRANGER straight at the app (the container's address — past the address block, the strictest case): sign-up refused; the user count before/after; 4 the household's 15-minute window (POST /apps//signup-window) → the open command; DB = true; a family member signs up straight at the app → success; the user count +1; 5 after the window ends (polled; ~15 min): the close command ran again; DB = false; a stranger refused; count unchanged. Evidence: ../E/live.txt.""" import json, os, secrets, 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 = "wishlist", "wishlist" HERE = os.path.dirname(os.path.abspath(__file__)) log = open(os.path.join(HERE, "..", "E", "live.txt"), "a", buffering=1) def say(*a): w.say(*a); log.write(" ".join(map(str, a)) + "\n") DBJS = r'''const {DatabaseSync}=require('node:sqlite');const db=new DatabaseSync('/usr/src/app/data/prod.db',{readOnly:true}); const v=db.prepare("select value from system_config where key='enableSignup' and groupId='global'").get(); const n=db.prepare("select count(*) as n from user").get();console.log('DB enableSignup='+(v?v.value:'')+' users='+n.n);''' def db(): return w.guest("docker exec -i wishlist node - <<'JS'\n" + DBJS + "\nJS\n").strip().splitlines()[-1:] def stranger(tag): """A sign-up straight at the app's own address inside the box — past the box's address block.""" u = f"{tag}{secrets.token_hex(3)}" body = f"name={tag}&username={u}&email={u}%40example.invalid&password=Drill-{secrets.token_hex(8)}&tokenId=" out = w.guest(f"""ip=$(docker inspect -f '{{{{range .NetworkSettings.Networks}}}}{{{{.IPAddress}}}} {{{{end}}}}' wishlist | awk '{{print $1}}') curl -s -m 30 -H 'Host: {SUB}.{w.DOMAIN}' -H 'Origin: https://{SUB}.{w.DOMAIN}' -H 'x-sveltekit-action: true' \\ -H 'Content-Type: application/x-www-form-urlencoded' -w '\\nHTTP %{{http_code}}' --data '{body}' http://$ip:3000/signup""") return " ".join(out.split())[-220:] def ctl_lines(since): return w.guest(f"docker logs --since {since} felhom-controller 2>&1 | grep -v DEBUG | grep -i -E 'after_setup|native|signup|sign-up|window' | cut -c1-300") w.login() if w.stack(APP).get("deployed"): say("wishlist installed from the earlier probe — removing it first (scratch box)") w.remove(APP) w.sync_rescan() time.sleep(5) w.sync_rescan() say("9202 controller:", w.guest("docker inspect -f '{{.Config.Image}}' felhom-controller").strip()) if not w.deploy(APP, SUB): sys.exit(say("RESULT install failed") or 1) fx = fixtures.FIXTURES[APP] tok = fx.seed(w, SUB, say) say("[1] the household's first account:", tok is not None, "| DB:", db()) t0 = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip() code, d = w.ctl("POST", f"/apps/{APP}/setup-gate/open", {}) say("[2] the household opens the app (setup done) ->", code, str(d)[:160]) time.sleep(25) say("[2] DB after the close command:", db()) log.write(ctl_lines(t0) + "\n") say("[3] stranger, straight at the app:", stranger("stranger")) say("[3] DB:", db()) t1 = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip() code, d = w.ctl("POST", f"/apps/{APP}/signup-window", {}) say("[4] the household opens the 15-minute window ->", code, str(d)[:160]) time.sleep(25) say("[4] DB inside the window:", db()) say("[4] a family member, straight at the app:", stranger("family")) say("[4] DB:", db()) log.write(ctl_lines(t1) + "\n") t2 = time.time() while time.time() - t2 < 1500: time.sleep(30) v = db() if v and "enableSignup=false" in v[0]: say(f"[5] the switch reads CLOSED again {round(time.time() - t2)} s after the check began: {v}") break else: say("[5] the switch did NOT close within 25 minutes:", db()) say("[5] stranger after the window, straight at the app:", stranger("late")) say("[5] DB:", db()) log.write(ctl_lines(t1) + "\n") st = w.stack(APP) say("[5] app page record:", json.dumps({k: (st.get("app_config") or {}).get(k) for k in ("after_setup", "setup_gate")})[:600]) if not os.environ.get("KEEP"): say("remove ->", w.remove(APP))