Files
cc-ci/runner/adv_check_wc2.py

88 lines
4.8 KiB
Python

#!/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)