64 lines
2.7 KiB
Python
64 lines
2.7 KiB
Python
"""Preserve exact current source bytes before a gate and read them back after it."""
|
|
import datetime
|
|
import hashlib
|
|
import json
|
|
import pathlib
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import zipfile
|
|
|
|
root = pathlib.Path(__file__).resolve().parents[2]
|
|
evidence = pathlib.Path(__file__).resolve().parent
|
|
mode, label = sys.argv[1:]
|
|
assert re.fullmatch(r"inputs[0-9]+", label)
|
|
|
|
def paths():
|
|
result = subprocess.run(["git", "ls-files", "-z", "--cached", "--others", "--exclude-standard", "--",
|
|
"crates", ".cargo", "Cargo.toml", "Cargo.lock", "docs", "examples", "harness/fixtures"],
|
|
cwd=root, check=True, capture_output=True)
|
|
return sorted(set(p.decode("utf-8") for p in result.stdout.split(b"\0") if p))
|
|
|
|
def data(path):
|
|
target = (root / path).resolve()
|
|
assert target.is_relative_to(root) and target.is_file(), path
|
|
return target.read_bytes()
|
|
|
|
def sha(raw):
|
|
return hashlib.sha256(raw).hexdigest()
|
|
|
|
def write(path, value):
|
|
with path.open("x", encoding="utf-8", newline="\n") as out:
|
|
json.dump(value, out, indent=2, ensure_ascii=False)
|
|
out.write("\n")
|
|
|
|
if mode == "capture":
|
|
entries = []
|
|
archive = evidence / (label + ".zip")
|
|
with zipfile.ZipFile(archive, "x", zipfile.ZIP_DEFLATED) as out:
|
|
for path in paths():
|
|
raw = data(path)
|
|
out.writestr(path, raw)
|
|
entries.append({"path": path, "bytes": len(raw), "sha256": sha(raw)})
|
|
result = {"atUtc": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
|
"head": subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=root).decode().strip(),
|
|
"branch": subprocess.check_output(["git", "branch", "--show-current"], cwd=root).decode().strip(),
|
|
"scope": "Exact Windows gate source inputs; no compiler or native result implied.",
|
|
"archiveSha256": sha(archive.read_bytes()), "files": entries}
|
|
write(evidence / (label + ".json"), result)
|
|
print(json.dumps({"files": len(entries), "bytes": sum(e["bytes"] for e in entries), "archiveSha256": result["archiveSha256"]}))
|
|
elif mode == "verify":
|
|
before = json.loads((evidence / (label + ".json")).read_text(encoding="utf-8"))
|
|
current = paths()
|
|
expected = [e["path"] for e in before["files"]]
|
|
changed = [e["path"] for e in before["files"] if sha(data(e["path"])) != e["sha256"]]
|
|
result = {"atUtc": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
|
"changed": changed, "added": sorted(set(current) - set(expected)),
|
|
"removed": sorted(set(expected) - set(current))}
|
|
result["passed"] = not any(result[k] for k in ("changed", "added", "removed"))
|
|
write(evidence / (label + "-readback.json"), result)
|
|
print(json.dumps(result))
|
|
sys.exit(0 if result["passed"] else 1)
|
|
else:
|
|
raise ValueError(mode)
|