Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
115 lines
4.1 KiB
Python
115 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Independently verify Visual-only frontmatter changes against the original private bundle."""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
def read(root, name):
|
|
path = root / name
|
|
if (
|
|
Path(name).is_absolute()
|
|
or ".." in Path(name).parts
|
|
or any(p.is_symlink() for p in (path, *path.parents))
|
|
):
|
|
raise ValueError("unsafe source path")
|
|
info = path.stat()
|
|
if (
|
|
not path.is_file()
|
|
or info.st_uid != os.getuid()
|
|
or info.st_mode & 0o077
|
|
or info.st_nlink != 1
|
|
or info.st_size > 16 * 1024 * 1024
|
|
):
|
|
raise ValueError("private bounded source required")
|
|
return path.read_bytes()
|
|
|
|
|
|
def verify(source, out):
|
|
if not __debug__:
|
|
raise ValueError("verification assertions required")
|
|
old = json.loads(read(source, "reconciliation.json"))
|
|
new = json.loads(read(out, "reconciliation.json"))
|
|
def sha(raw):
|
|
return hashlib.sha256(raw).hexdigest()
|
|
assert new["original_report_sha256"] == sha(read(source, "reconciliation.json"))
|
|
assert read(out, "source-capture/reconciliation-before-visuals.json") == read(
|
|
source, "reconciliation.json"
|
|
)
|
|
for name, digest in new["file_sha256"].items():
|
|
assert sha(read(out, name)) == digest
|
|
changed = 0
|
|
for name, digest in old["file_sha256"].items():
|
|
original = read(source, name)
|
|
current = read(out, name)
|
|
assert sha(original) == digest
|
|
if current != original:
|
|
assert "/pages/" in name and name.endswith(".md")
|
|
before, body = original.split(b"\n---\n", 1)
|
|
after, after_body = current.split(b"\n---\n", 1)
|
|
assert body == after_body
|
|
assert (
|
|
len(re.findall(rb'^visual: "assets/[a-f0-9]{64}\.(?:png|jpg|webp)"$', after, re.M))
|
|
== 1
|
|
)
|
|
if name.endswith("/index.md"):
|
|
restored = re.sub(
|
|
rb'\nvisual: "assets/[a-f0-9]{64}\.(?:png|jpg|webp)"$', b"", after
|
|
)
|
|
else:
|
|
restored = re.sub(
|
|
rb'^visual: "assets/[a-f0-9]{64}\.(?:png|jpg|webp)"$',
|
|
b'visual: ""',
|
|
after,
|
|
flags=re.M,
|
|
)
|
|
assert restored == before
|
|
changed += 1
|
|
for axis in ["unassigned_article_ids", "source_sha256"]:
|
|
assert new[axis] == old[axis]
|
|
assert len(old["spaces"]) == len(new["spaces"])
|
|
for a, b in zip(old["spaces"], new["spaces"], strict=True):
|
|
assert a["blockers"] == b["blockers"] and not b["import_ready"]
|
|
for key in a:
|
|
if key != "articles":
|
|
assert a[key] == b[key], key
|
|
for x, y in zip(a["articles"], b["articles"], strict=True):
|
|
assert {k: v for k, v in x.items() if k != "file_sha256"} == {
|
|
k: v for k, v in y.items() if k != "file_sha256"
|
|
}
|
|
for p in out.rglob("*"):
|
|
assert p.stat().st_mode & 0o077 == 0
|
|
return {
|
|
"schema": "coulomb.visual-preservation-proof.v1",
|
|
"verified_output_files": len(new["file_sha256"]),
|
|
"verified_original_files": len(old["file_sha256"]),
|
|
"frontmatter_only_changes": changed,
|
|
"all_source_bodies_and_dates_preserved": True,
|
|
"spaces_preserved": len(new["spaces"]),
|
|
"original_blockers_preserved": True,
|
|
"unassigned_records_preserved": True,
|
|
"private_modes_verified": True,
|
|
"private_bundle_sha256": sha(read(out, "reconciliation.json")),
|
|
"production_imported": False,
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("original", type=Path)
|
|
parser.add_argument("prepared", type=Path)
|
|
args = parser.parse_args()
|
|
try:
|
|
print(json.dumps(verify(args.original, args.prepared)))
|
|
except Exception:
|
|
print("Private visual preservation verification failed; no acceptance inferred.")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|