🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
#!/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")