#!/usr/bin/env python3 """ADVERSARY WC2+WC3 cold reproduce (data-warm canonical round-trip). Run via cc-ci-run from /root/cc-ci-adv-verify. Drives the cycle MYSELF (does not trust the Builder's single run): 1. deploy_canonical -> reattach the retained volume; confirm the Builder's known-good marker is served 2. WC2: write MY OWN marker -> undeploy_keep_volume (assert app DOWN + volume RETAINED) -> deploy_canonical -> MY marker SURVIVES (data-warm reattach) 3. WC3: mutate (delete the known-good marker) -> undeploy -> warmsnap.restore -> deploy -> known-good marker BACK and my marker GONE (restore round-trips the exact known-good) 4. leave it idle (as found): undeploy_keep_volume; content == known-good """ import os, subprocess, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from harness import canonical, lifecycle, warmsnap R = "custom-html" D = "warm-custom-html.ci.commoninternet.net" HTML = "/usr/share/nginx/html" KG = "WC2-DATA-MARKER-7f3a9c" # the Builder's known-good marker string A = "ADV-OWN-MARKER-a1b2c3" # my own marker fails = [] def sh(*cmd): return lifecycle.exec_in_app(D, list(cmd), service="app") def has_service(): return bool(subprocess.run(["docker","service","ls","--format","{{.Name}}"], capture_output=True,text=True).stdout and any("custom-html" in n for n in subprocess.run(["docker","service","ls","--format","{{.Name}}"], capture_output=True,text=True).stdout.split())) def has_volume(): out = subprocess.run(["docker","volume","ls","--format","{{.Name}}"],capture_output=True,text=True).stdout return any("warm-custom-html" in n and n.endswith("_content") for n in out.split()) def serving(): r = subprocess.run(["curl","-sk","--resolve",f"{D}:443:127.0.0.1","-o","/dev/null", "-w","%{http_code}","--max-time","10",f"https://{D}/"],capture_output=True,text=True) return r.stdout.strip() print(f"START canonical={canonical.read_registry(R)} has_canonical={canonical.has_canonical(R)} " f"has_snapshot={warmsnap.has_snapshot(R)} service={has_service()} volume={has_volume()}") if not warmsnap.has_snapshot(R): fails.append("no snapshot present at start") # 1. reattach + confirm Builder's known-good marker survived their run canonical.deploy_canonical(R); listing = sh("ls", HTML) kg_files = sh("grep","-rl",KG,HTML).split() print(f"[1] deployed; serving={serving()} html={listing.split()} kg_marker_files={kg_files}") if not kg_files: fails.append("Builder known-good marker not found after reattach") kg_file = kg_files[0] if kg_files else None if serving() != "200": fails.append(f"[1] not serving 200: {serving()}") # 2. WC2: my own marker through undeploy-keep-volume -> redeploy sh("sh","-c",f"echo {A} > {HTML}/adv_own.txt") got = sh("cat",f"{HTML}/adv_own.txt").strip() print(f"[2] wrote my marker: {got!r}") canonical.undeploy_keep_volume(R) svc_down, vol_kept = not has_service(), has_volume() print(f"[2] after undeploy_keep_volume: service_down={svc_down} volume_retained={vol_kept} " f"registry_status={ (canonical.read_registry(R) or {}).get('status') }") if not svc_down: fails.append("[2] app still has a service after undeploy_keep_volume") if not vol_kept: fails.append("[2] content volume NOT retained (data-warm broken)") canonical.deploy_canonical(R) survived = sh("cat",f"{HTML}/adv_own.txt").strip() print(f"[2] after redeploy: my marker={survived!r}") if survived != A: fails.append(f"[2] my marker did NOT survive data-warm round-trip: {survived!r}") # 3. WC3: mutate (delete known-good marker) -> undeploy -> restore -> deploy -> known-good BACK if kg_file: sh("rm", "-f", kg_file) mutated_gone = not sh("grep", "-rl", KG, HTML).split() print(f"[3] mutated: deleted known-good marker file {kg_file}; gone_now={mutated_gone}") canonical.undeploy_keep_volume(R) warmsnap.restore(R, D) canonical.deploy_canonical(R) kg_back = bool(sh("grep", "-rl", KG, HTML).split()) a_present = "adv_own.txt" in sh("ls", HTML).split() print(f"[3] after restore+deploy: known_good_back={kg_back} my_marker_still_there={a_present}") if not kg_back: fails.append("[3] known-good marker NOT restored (WC3 restore failed)") if a_present: fails.append("[3] my marker still present after restore — restore not exact known-good") # 4. leave idle as found canonical.undeploy_keep_volume(R) print(f"END registry={canonical.read_registry(R)} service={has_service()} volume={has_volume()}") if has_service(): fails.append("[4] left a running service (should be idle)") if not has_volume(): fails.append("[4] volume not retained at end") print("\nRESULT:", "FAIL: "+"; ".join(fails) if fails else "PASS — WC2 data-warm round-trip (my own marker survives undeploy-keep-volume+reattach) + WC3 " "restore round-trips the exact known-good; left idle with volume retained") sys.exit(1 if fails else 0)