#!/usr/bin/env python3 """floatpush.py — Part C (2026-09-30): for every FLOATING line in the live catalog (the currency audit's definition: fewer than three numbers in the tag's first version run), (1) does the registry serve today the digest the newest ladder entry TESTED for it, and (2) when was the tag last pushed (Docker Hub `tag_last_pushed`; ghcr/lscr have no anonymous timestamp — said, not guessed). Read-only; the audit's helpers are imported.""" import importlib.util, json, os, re, sys, datetime, requests CAT = "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu" A = "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/catalog-currency-2026-09-30/00-currency.py" sys.argv = ["x", CAT, "/dev/null"] s = importlib.util.spec_from_file_location("c", A); c = importlib.util.module_from_spec(s); s.loader.exec_module(c) sys.path.insert(0, CAT + "/scripts"); import ladder now = datetime.datetime.now(datetime.timezone.utc) print(f"# floating lines in the live catalog, read {now.isoformat(timespec='seconds')}") lines = {} for app in sorted(os.listdir(CAT + "/templates")): d = f"{CAT}/templates/{app}" imgs = ladder.images_in(open(d + "/docker-compose.yml").read()) entries, _, _ = ladder.parse(open(d + "/.felhom.yml").read()) for svc, ref in imgs.items(): repo, tag = c.split_ref(ref) if not c.is_floating(tag): continue tested = None for e in reversed(entries or []): if e.get("to", {}).get(svc) == ref: tested = (e.get("digest") or {}).get(svc); break lines.setdefault(ref, []).append((app, svc, tested)) recent = 0 for ref, uses in sorted(lines.items()): repo, tag = c.split_ref(ref); host, r = c.host_repo(repo) try: now_d = c.digest(host, r, tag) now_d = now_d[0] if isinstance(now_d, tuple) else now_d except Exception as e: now_d = f"ERR {e!r}"[:60] pushed = "no anonymous timestamp on " + host if host == "registry-1.docker.io": try: j = requests.get(f"https://hub.docker.com/v2/repositories/{r}/tags/{tag}", timeout=30).json() pushed = j.get("tag_last_pushed") or j.get("last_updated") or "?" age = (now - datetime.datetime.fromisoformat(pushed.replace("Z", "+00:00"))).days pushed = f"{pushed} ({age} days ago)" if age <= 30: recent += 1 except Exception as e: pushed = f"ERR {e!r}"[:80] print(f"\n{ref} last pushed: {pushed}\n registry digest today: {str(now_d)[:19]}") for app, svc, tested in uses: st = "no ladder digest" if not tested else ("= tested" if tested == now_d else f"MOVED since the test (tested {tested[:19]})") print(f" {app}/{svc}: {st}") print(f"\n# {len(lines)} distinct floating lines; Docker Hub lines pushed within 30 days: {recent}")