#!/usr/bin/env python3 """summarize.py RUNS_DIR: one table row per run, then the verdict per pre-registered prediction. Reads every RUNS_DIR/*/result.json written by inside.py. Prints Markdown. Definitions are the ones in PREREG-probe.md: a lookup is a query the fake DNS logged; a collector attempt is a connection the fake TLS listener accepted with SNI = the collector; an inet syscall is any strace connect/send to an AF_INET/AF_INET6 address (AF_UNIX is local and not counted). """ import glob import json import os import sys COLLECTOR = "mobile.events.data.microsoft.com" N_SECONDS = 60 EXPECT_ATTEMPTS = {"posctl": "P0", "ort130-default": "P1", "ort130-apioff": "P3", "ort129-default": "P4"} EXPECT_SILENCE = {"ort130-envoff": "P2", "ort128-default": "P5"} def facts(r): dns = r.get("dns", []) tls = r.get("tls", []) inet = [c for c in (r.get("strace") or []) if c["family"] != "AF_UNIX"] lookups = [d["t_rel_s"] for d in dns if d["name"] == COLLECTOR] attempts = [t["t_rel_s"] for t in tls if t.get("sni") == COLLECTOR] q = r.get("queue", {}) rows = q.get("rows", []) return { "void": r.get("void") or (not r.get("selftest", {}).get("pass")), "rc": r.get("subject_rc"), "lookups": lookups, "other_dns": sorted({f'{d["name"]}/{d["qtype"]}' for d in dns if d["name"] != COLLECTOR}), "qtypes": sorted({d["qtype"] for d in dns if d["name"] == COLLECTOR}), "attempts": attempts, "other_tls": [t.get("sni") for t in tls if t.get("sni") != COLLECTOR], "http": len(r.get("http", [])), "inet": inet, "inet_not_sink": [c for c in inet if c["dst"] not in ("127.0.0.1:53", "127.0.0.2:443")], "strace_443": [c["t_rel_s"] for c in inet if c["call"] == "connect" and c["dst"] == "127.0.0.2:443"], "deviceid": r.get("deviceid", {}).get("exists"), "db": q.get("db_exists"), "rows": rows, "events": sorted({e for row in rows for e in row["events"]}), "canaries": sorted({c for row in rows for c in row["canaries"]}), "ses": r.get("tmp_ses", {}).get("exists"), "alpn": sorted({",".join(t.get("alpn") or []) for t in tls if t.get("sni") == COLLECTOR}), } def fmt_times(ts, n=6): s = ", ".join(f"{t:.1f}" for t in ts[:n]) return s + (f" … (+{len(ts) - n})" if len(ts) > n else "") def main(runs_dir): results = [] for p in sorted(glob.glob(os.path.join(runs_dir, "*", "result.json"))): with open(p) as f: results.append(json.load(f)) order = ["posctl", "ort130-default", "ort130-envoff", "ort130-apioff", "ort129-default", "ort128-default"] results.sort(key=lambda r: (order.index(r["arm"]) if r["arm"] in order else 99, str(r["rep"]))) print("| arm | rep | exit | self-test | collector lookups (n; s after launch) | TLS attempts, SNI = collector " "(n; s after launch) | inet syscalls (n; to anything but the two sinks) | deviceid / queue db / /tmp/.ses " "| queue rows after exit | event names in queue | canaries in queue |") print("|---|---|---|---|---|---|---|---|---|---|---|") by_arm = {} for r in results: f = facts(r) by_arm.setdefault(r["arm"], []).append(f) yn = lambda b: "yes" if b else "no" print(f'| {r["arm"]} | {r["rep"]} | {f["rc"]} | {"VOID" if f["void"] else "pass"} ' f'| {len(f["lookups"])}; {fmt_times(f["lookups"])} | {len(f["attempts"])}; {fmt_times(f["attempts"])} ' f'| {len(f["inet"])}; {len(f["inet_not_sink"])} ' f'| {yn(f["deviceid"])} / {yn(f["db"])} / {yn(f["ses"])} | {len(f["rows"])} ' f'| {", ".join(f["events"]) or "-"} | {", ".join(f["canaries"]) or "-"} |') print("\n## Verdicts against PREREG-probe.md\n") for arm, pid in {**EXPECT_ATTEMPTS, **EXPECT_SILENCE}.items(): runs = [f for f in by_arm.get(arm, []) if not f["void"]] if not runs: print(f"- **{pid} {arm}**: NO VALID RUNS") continue if arm in EXPECT_ATTEMPTS: ok = [any(t <= N_SECONDS for t in f["lookups"]) and any(t <= N_SECONDS for t in f["attempts"]) for f in runs] claim = f"≥1 collector lookup and ≥1 collector TLS attempt within {N_SECONDS} s" else: ok = [not f["lookups"] and not f["attempts"] and not f["other_dns"] and not f["other_tls"] and not f["http"] and not f["inet"] for f in runs] claim = "0 lookups, 0 TLS/HTTP attempts, 0 inet syscalls" verdict = "CONFIRMED" if all(ok) and len(runs) >= 3 else ("REFUTED" if not all(ok) else "INCOMPLETE") print(f"- **{pid} {arm}**: {verdict}: {claim}: held in {sum(ok)}/{len(runs)} valid runs") if __name__ == "__main__": main(sys.argv[1] if len(sys.argv) > 1 else os.path.join(os.path.dirname(os.path.abspath(__file__)), "runs"))