88 lines
4.8 KiB
Python
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)
|