42bf40bd2c
gates / gates (push) Successful in 29s
- Twelve steps published on both venues (catalog): first ladders for calibre-web, gitea, wger, crafty-controller, uptime-kuma, zipline (two steps); within-major emby, ghost, home-assistant, outline, rallly. immich's step v3.0.3 -> v3.2.2 re-proven at 768M (Part D). - Part C: the night leg skips a digest-only change AND the catalog never records a same-tag re-test, so a same-name upstream fix reaches no box. Row R-740; the decision in STATUS; `09` decision 30 carries a dated note (the decision itself unchanged). - Rows: 369 -> 377. Opened R-735..R-742; closed R-735, R-738, R-742; narrowed R-462, R-624, R-446, R-440, R-734, R-732. The currency audit gains §1b (and corrects its 31+1 to 30+2). Evidence: documentation/audits/more-night-apps-2026-09-30/. Report: REPORT-more-night-apps-2026-09-30.md. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
25 lines
1.4 KiB
Python
25 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
"""digestread.py — READ-ONLY (login + GET only): per deployed app, the catalog's tested digest (catalog_digests,
|
|
catalog_tested_at) vs app.yaml installed_images (ref, digest, at), and the badge order the box computes.
|
|
GUEST=9201 BASE=https://<ip> for demo-hp's standing guest. Part C (the same-name security fix)."""
|
|
import json, os, sys
|
|
import walk as w
|
|
w.login()
|
|
c, d = w.ctl("GET", "/api/stacks")
|
|
data = d.get("data") if isinstance(d, dict) else d
|
|
stacks = data if isinstance(data, list) else (data or {}).get("stacks", [])
|
|
print(f"# guest {w.GUEST} {w.BASE} — read-only")
|
|
for s in sorted(stacks, key=lambda x: x.get("name", "")):
|
|
if not s.get("deployed"):
|
|
continue
|
|
st = w.stack(s["name"])
|
|
ac = st.get("app_config") or {}
|
|
cd = st.get("catalog_digests") or {}
|
|
print(f"{s['name']} | update_order={st.get('update_order')!r} badge={st.get('update_badge') or st.get('badge')!r} catalog_tested_at={st.get('catalog_tested_at')}")
|
|
for svc, rec in sorted((ac.get("installed_images") or {}).items()):
|
|
ref = rec.get("ref") if isinstance(rec, dict) else rec
|
|
dg = (rec.get("digest") if isinstance(rec, dict) else "") or ""
|
|
at = rec.get("at") if isinstance(rec, dict) else ""
|
|
cat = cd.get(svc, "")
|
|
print(f" {svc}: {ref} installed={dg[7:19] or '-'} at={at} catalog={cat[7:19] or '-'} equal={bool(cat) and cat == dg}")
|