Source identity
| Field | Recorded value |
|---|---|
| Source type | archive member |
| Original record | 06_verify.py |
| Date | Not specified in source |
| Path or archive member | archives/libsrc-1c3f88063121/NETLIFY_AI_RECOVERY_2026-10-14_21-10-49/scripts/06_verify.py |
| Original SHA-256 | ade9ad743af4b16de5a54f6badbe6b2324412d22dc2a2cba166ef810d5d0eb7c |
| Reading-copy SHA-256 | ade9ad743af4b16de5a54f6badbe6b2324412d22dc2a2cba166ef810d5d0eb7c |
| Archive source | {"sourceId": "libsrc-1c3f88063121", "member": "NETLIFY_AI_RECOVERY_2026-10-14_21-10-49/scripts/06_verify.py"} |
Recovered source transcript
Download complete source text ↓155 lines · 7.5 KB
"""Phase 6: verify every archive and write CHECKSUMS.sha256 and checkpoints/verification.json."""
import glob
import hashlib
import json
import os
import re
import subprocess
import sys
import tempfile
import zipfile
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from nlr_common import ROOT, log, now, sha256_file, write_json
HTMLISH = re.compile(rb"^\s*(<!doctype html|<html)", re.I)
def unzip_test(p):
r = subprocess.run(["unzip", "-tqq", p], capture_output=True, text=True)
return r.returncode == 0, (r.stdout + r.stderr).strip()[-300:]
def safe_entry(n):
return not (n.startswith("/") or ".." in n.split("/") or "\x00" in n)
def verify_deploy_zip(zp, man):
want = {e["local_path"]: e for e in man["files"] if not e.get("error")}
res = {"expected_entries": len(want), "matched_sha1": 0, "mismatched": [], "missing_in_zip": [], "extra_in_zip": [],
"unsafe_names": [], "html_where_asset_expected": []}
with zipfile.ZipFile(zp) as z:
names = [i.filename for i in z.infolist() if not i.is_dir()]
res["unsafe_names"] = [n for n in names if not safe_entry(n)]
res["extra_in_zip"] = sorted(set(names) - set(want))
res["missing_in_zip"] = sorted(set(want) - set(names))
for n in names:
if n not in want:
continue
h = hashlib.sha1()
first = b""
size = 0
with z.open(n) as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
if not first:
first = chunk[:200]
h.update(chunk)
size += len(chunk)
e = want[n]
if h.hexdigest() == e["sha1_manifest"] and (e.get("size_manifest") in (None, size)):
res["matched_sha1"] += 1
else:
res["mismatched"].append(n)
mt = (e.get("mime_type") or "").lower()
if HTMLISH.match(first) and "html" not in mt and not n.lower().endswith((".html", ".htm")):
res["html_where_asset_expected"].append(n)
res["passed"] = (res["matched_sha1"] == len(want) and not res["mismatched"] and not res["missing_in_zip"]
and not res["extra_in_zip"] and not res["unsafe_names"])
return res
def verify_source_zip(zp, mirror, commit):
r = subprocess.run(["git", "ls-tree", "-r", "-z", commit], cwd=mirror, capture_output=True)
blobs = [x for x in r.stdout.split(b"\0") if x and b" blob " in x.split(b"\t")[0]]
with zipfile.ZipFile(zp) as z:
files = [i for i in z.infolist() if not i.is_dir()]
unsafe = [i.filename for i in files if not safe_entry(i.filename)]
return {"git_tree_blobs": len(blobs), "zip_file_entries": len(files), "unsafe_names": unsafe,
"passed": len(blobs) == len(files) and not unsafe}
def verify_history_zip(zp):
with tempfile.TemporaryDirectory(dir=os.path.join(ROOT, "tmp")) as td:
with zipfile.ZipFile(zp) as z:
z.extract("repository_all_refs.bundle", td)
b = os.path.join(td, "repository_all_refs.bundle")
r = subprocess.run(["git", "bundle", "list-heads", b], capture_output=True, text=True)
heads = r.stdout.strip().splitlines()
r2 = subprocess.run(["git", "init", "-q", os.path.join(td, "v")], capture_output=True)
r3 = subprocess.run(["git", "-C", os.path.join(td, "v"), "bundle", "verify", b], capture_output=True, text=True)
return {"bundle_heads": len(heads), "bundle_verify_ok": r3.returncode == 0, "passed": r.returncode == 0 and r3.returncode == 0 and bool(heads)}
def main():
desktop = os.path.realpath(os.path.expanduser("~/Desktop"))
out = {"verified_at": now(), "root": ROOT, "root_is_on_users_desktop": os.path.realpath(ROOT).startswith(desktop + os.sep),
"archives": {}}
manifests = {}
for mp in glob.glob(os.path.join(ROOT, "sites", "*", "manifests", "deploy_*_recovery.json")):
m = json.load(open(mp))
if m.get("zip"):
manifests[os.path.basename(m["zip"]["path"])] = m
lines = []
for zp in sorted(glob.glob(os.path.join(ROOT, "zips", "*.zip"))):
bn = os.path.basename(zp)
rec = {"bytes": os.path.getsize(zp), "sha256": sha256_file(zp)}
rec["unzip_test_ok"], rec["unzip_test_output"] = unzip_test(zp)
try:
if "__DEPLOY__" in bn:
m = manifests.get(bn)
rec["kind"] = "DEPLOY"
rec["content"] = verify_deploy_zip(zp, m) if m else {"passed": False, "error": "no recovery manifest"}
if m:
rec["deploy_status"] = m["status"]
rec["manifest_sha256_matches"] = (m["zip"]["sha256"] == rec["sha256"])
elif "__SOURCE__" in bn:
rec["kind"] = "SOURCE"
commit = bn.rsplit("__SOURCE__", 1)[1][:-4]
site_dir = glob.glob(os.path.join(ROOT, "sites", "*__" + bn.split("__")[1]))[0]
mirror = glob.glob(os.path.join(site_dir, "source", "*.git"))[0]
rec["content"] = verify_source_zip(zp, mirror, commit)
elif "__REPOSITORY_HISTORY" in bn:
rec["kind"] = "REPOSITORY_HISTORY"
rec["content"] = verify_history_zip(zp)
elif "__PUBLIC_MIRROR_PARTIAL__" in bn:
rec["kind"] = "PUBLIC_MIRROR_PARTIAL"
with zipfile.ZipFile(zp) as z:
names = z.namelist()
rec["content"] = {"entries": len(names), "passed": all(safe_entry(n) for n in names)}
else:
rec["kind"] = "OTHER"
rec["content"] = {"passed": rec["unzip_test_ok"]}
except Exception as e:
rec["content"] = {"passed": False, "error": f"{type(e).__name__}: {e}"}
rec["passed"] = bool(rec["unzip_test_ok"] and rec["content"].get("passed") and rec["bytes"] > 22)
out["archives"][bn] = rec
lines.append(f"{rec['sha256']} zips/{bn}")
log(f"verify {bn}: {'PASS' if rec['passed'] else 'FAIL'} ({rec['bytes']} bytes)", echo=False)
# Recovered individual files (from manifests; recomputed only for the content store spot check below).
for mp in sorted(glob.glob(os.path.join(ROOT, "sites", "*", "manifests", "deploy_*_recovery.json"))):
m = json.load(open(mp))
site_rel = os.path.relpath(os.path.dirname(os.path.dirname(mp)), ROOT)
for e in m["files"]:
if e.get("sha256"):
lines.append(f"{e['sha256']} {site_rel}/originals/deploy_{m['deploy']['id']}/{e['local_path']}")
with open(os.path.join(ROOT, "CHECKSUMS.sha256.tmp"), "w") as f:
f.write("\n".join(lines) + "\n")
os.replace(os.path.join(ROOT, "CHECKSUMS.sha256.tmp"), os.path.join(ROOT, "CHECKSUMS.sha256"))
# Re-hash every recovered original on disk against the checksum list.
bad = 0
for ln in lines:
h, rel = ln.split(" ", 1)
if not rel.startswith("zips/") and sha256_file(os.path.join(ROOT, rel)) != h:
bad += 1
out["original_files_checked"] = sum(1 for ln in lines if not ln.split(" ", 1)[1].startswith("zips/"))
out["original_files_hash_mismatch"] = bad
out["archives_total"] = len(out["archives"])
out["archives_passed"] = sum(1 for r in out["archives"].values() if r["passed"])
write_json(os.path.join(ROOT, "checkpoints", "verification.json"), out)
log(f"verification: {out['archives_passed']}/{out['archives_total']} archives passed; "
f"{out['original_files_checked']} original files rechecked, {bad} mismatches; on Desktop={out['root_is_on_users_desktop']}")
if __name__ == "__main__":
main()