#!/usr/bin/env python3 """Rozstrzyga 14 przypadkow CONTENT_DIFF: czy https serwuje ten sam plik co http. Dla kazdego wystapienia: - key == 'url' (strona domowa, nie jest pobierana przy buildzie) -> uznaj za OK - key == 'source': * jesli receptura ma realna sume dla tego zrodla -> pobierz https i porownaj sume * inaczej -> pobierz http i https, porownaj sha256 obu Wynik: lista ZWERYFIKOWANYCH (mozna bezpiecznie podmienic) i ODRZUCONYCH. """ import hashlib import json import os import re import subprocess import sys import tempfile import yaml R = "/var/lib/pagan-sync/recipes" PH = re.compile(r"\$\{([A-Za-z_][A-Za-z0-9_]*)\}") audit = json.load(open("/tmp/https-audit.json")) entries = audit.get("CONTENT_DIFF", []) def as_list(v): if v is None: return [] return v if isinstance(v, list) else [v] def expand(s, d): def rep(m): k = m.group(1) return str(d[k]) if k in d and not isinstance(d[k], (dict, list)) else m.group(0) return PH.sub(rep, s) def fetch_sha(url): """Pobiera URL do temp i zwraca sha256 (lub None).""" fd, path = tempfile.mkstemp(prefix="pagvd-") os.close(fd) try: p = subprocess.run(["curl", "-sS", "-L", "--max-time", "300", "-o", path, "-w", "%{http_code}", "-A", "curl/8.7.1", url], capture_output=True, text=True) code = (p.stdout or "").strip() if code != "200": return None, f"HTTP {code}" h = hashlib.sha256() with open(path, "rb") as f: for chunk in iter(lambda: f.read(1 << 20), b""): h.update(chunk) return h.hexdigest(), "ok" finally: try: os.unlink(path) except OSError: pass verified, rejected = [], [] for e in entries: rel, key, raw, exp = e["recipe"], e["key"], e["raw"], e["expanded"] d = yaml.safe_load(open(f"{R}/{rel}", newline="", encoding="utf-8")) or {} if key == "url": verified.append((rel, key, raw, "strona domowa - https dziala")) continue srcs = as_list(d.get("source")) sums = as_list(d.get("sha256sums")) try: idx = [str(s) for s in srcs].index(raw) except ValueError: rejected.append((rel, key, raw, "nie znaleziono w source")) continue recorded = str(sums[idx]) if idx < len(sums) else None https_url = "https://" + expand(raw, d)[len("http://"):] if recorded and not recorded.strip().upper().startswith("SKIP"): got, note = fetch_sha(https_url) if got == recorded: verified.append((rel, key, raw, f"sha256 https == suma w recepturze ({note})")) else: rejected.append((rel, key, raw, f"sha256 https={got} != suma w recepturze={recorded} ({note})")) else: http_url = expand(raw, d) h1, n1 = fetch_sha(http_url) h2, n2 = fetch_sha(https_url) if h1 and h2 and h1 == h2: verified.append((rel, key, raw, f"sha256 http == https ({n1}/{n2})")) else: rejected.append((rel, key, raw, f"http={h1}({n1}) https={h2}({n2})")) print(f"ZWERYFIKOWANE ({len(verified)}):") for v in verified: print(f" OK {v[0]} [{v[1]}] {v[3]}") print(f"\nODRZUCONE ({len(rejected)}):") for v in rejected: print(f" NIE {v[0]} [{v[1]}] {v[3]}") print(f" {v[2][:100]}") json.dump({"verified": verified, "rejected": rejected, "verified_urls": [v[2] for v in verified]}, open("/tmp/content-diff-verdict.json", "w"), indent=1, ensure_ascii=False) print("\nzapisano /tmp/content-diff-verdict.json")