review(2): resume checkpoint — no gate pending; drone block genuine (/etc/timezone still absent on host); leftover drone smoke stack flagged (housekeeping); immich P4-restore still OPEN, unsigned
This commit is contained in:
81
runner/adv_check6.py
Normal file
81
runner/adv_check6.py
Normal file
@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""ADVERSARY check6 — WC1.2 pre-deploy SAFETY gate (live, cold). A hold must do NO deploy.
|
||||
(a) MAJOR fake tag 11.0.0+27.0.0 -> held-major, alert, kc untouched (TYPE same, 200)
|
||||
(b) minor tag 10.7.2+26.6.3 + releaseNotes flagging manual migration -> held-manual-migration,
|
||||
alert CARRIES the notes, kc untouched
|
||||
Leaves the recipe + kc exactly as found (canonical, no fake tags/notes)."""
|
||||
import json, os, subprocess, sys
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import warm_reconcile as wr
|
||||
|
||||
D = "warm-keycloak.ci.commoninternet.net"
|
||||
RDIR = os.path.expanduser("~/.abra/recipes/keycloak")
|
||||
GOOD = "04400df"; CANON = "10.7.1+26.6.2"
|
||||
T_MAJOR = "11.0.0+27.0.0"; T_MINOR = "10.7.2+26.6.3"
|
||||
NOTES = os.path.join(RDIR, "releaseNotes", T_MINOR + ".md")
|
||||
ALERTS = os.path.join(wr.warmsnap.DEFAULT_WARM_ROOT, "alerts")
|
||||
fails = []
|
||||
|
||||
def git(*a, check=True):
|
||||
return subprocess.run(["git", "-C", RDIR, "-c", "user.email=adv@cc-ci", "-c", "user.name=adv", *a],
|
||||
capture_output=True, text=True, check=check)
|
||||
def reconcile():
|
||||
env = {**os.environ, "CCCI_SKIP_FETCH": "1"}
|
||||
r = subprocess.run(["python3", os.path.join(os.path.dirname(__file__), "warm_reconcile.py"), "keycloak"],
|
||||
capture_output=True, text=True, env=env, timeout=300)
|
||||
for line in r.stdout.splitlines():
|
||||
if line.startswith("RECONCILE RESULT:"): return line.split(":", 1)[1].strip()
|
||||
return f"<no result rc={r.returncode}> {r.stdout[-300:]} {r.stderr[-300:]}"
|
||||
def alerts_now(): return set(os.listdir(ALERTS)) if os.path.isdir(ALERTS) else set()
|
||||
|
||||
type0, lg0 = wr.current_version(D), wr.read_last_good("keycloak")
|
||||
print(f"START TYPE={type0} last_good={lg0} health={wr.health_code(wr.SPECS['keycloak'])}")
|
||||
assert type0 == CANON, f"precond: kc not canonical ({type0})"
|
||||
|
||||
# (a) MAJOR -> held-major, no deploy
|
||||
git("reset", "--hard", GOOD)
|
||||
git("tag", "-a", "-m", "adv", T_MAJOR, GOOD + "^{commit}", check=False)
|
||||
a0 = alerts_now()
|
||||
res_a = reconcile()
|
||||
new_a = sorted(alerts_now() - a0)
|
||||
print(f"(a) MAJOR {T_MAJOR}: result={res_a!r} TYPE={wr.current_version(D)} new_alerts={new_a}")
|
||||
if not res_a.startswith("held-major"): fails.append(f"(a) not held-major: {res_a}")
|
||||
if wr.current_version(D) != CANON: fails.append(f"(a) kc TYPE changed to {wr.current_version(D)}")
|
||||
hm = [x for x in new_a if "held-major" in x]
|
||||
if not hm: fails.append("(a) no held-major alert")
|
||||
else:
|
||||
rec = json.load(open(os.path.join(ALERTS, hm[0])))
|
||||
if rec.get("latest") != T_MAJOR: fails.append(f"(a) alert latest={rec.get('latest')}")
|
||||
if "release_notes" not in rec: fails.append("(a) alert missing release_notes field")
|
||||
git("tag", "-d", T_MAJOR, check=False)
|
||||
|
||||
# (b) minor + manual-migration notes -> held-manual-migration, no deploy, alert carries notes
|
||||
git("tag", "-a", "-m", "adv", T_MINOR, GOOD + "^{commit}", check=False)
|
||||
os.makedirs(os.path.dirname(NOTES), exist_ok=True)
|
||||
open(NOTES, "w").write("# 10.7.2\n\nThis release requires a **manual migration**: run the DB upgrade by hand.\n")
|
||||
b0 = alerts_now()
|
||||
res_b = reconcile()
|
||||
new_b = sorted(alerts_now() - b0)
|
||||
print(f"(b) MINOR+migration {T_MINOR}: result={res_b!r} TYPE={wr.current_version(D)} new_alerts={new_b}")
|
||||
if not res_b.startswith("held-manual-migration"): fails.append(f"(b) not held-manual-migration: {res_b}")
|
||||
if wr.current_version(D) != CANON: fails.append(f"(b) kc TYPE changed to {wr.current_version(D)}")
|
||||
hmm = [x for x in new_b if "manual-migration" in x]
|
||||
if not hmm: fails.append("(b) no held-manual-migration alert")
|
||||
else:
|
||||
rec = json.load(open(os.path.join(ALERTS, hmm[0])))
|
||||
if "manual migration" not in (rec.get("release_notes") or "").lower():
|
||||
fails.append(f"(b) alert release_notes lacks the notes: {rec.get('release_notes')!r}")
|
||||
|
||||
# cleanup
|
||||
git("tag", "-d", T_MINOR, check=False)
|
||||
if os.path.exists(NOTES): os.remove(NOTES)
|
||||
git("reset", "--hard", GOOD)
|
||||
faketags = [t for t in git("tag").stdout.split() if t in (T_MAJOR, T_MINOR)]
|
||||
print(f"END TYPE={wr.current_version(D)} last_good={wr.read_last_good('keycloak')} "
|
||||
f"health={wr.health_code(wr.SPECS['keycloak'])} faketags={faketags} notes_exists={os.path.exists(NOTES)}")
|
||||
if wr.current_version(D) != CANON: fails.append(f"END not canonical: {wr.current_version(D)}")
|
||||
if faketags: fails.append(f"leftover fake tags {faketags}")
|
||||
if wr.read_last_good("keycloak") != CANON: fails.append(f"last_good moved to {wr.read_last_good('keycloak')}")
|
||||
|
||||
print("\nRESULT:", "FAIL: " + "; ".join(fails) if fails else "PASS — WC1.2 holds major + manual-migration with notes-carrying alert; kc untouched (no deploy/last_good churn)")
|
||||
sys.exit(1 if fails else 0)
|
||||
Reference in New Issue
Block a user