← Files Canonical Memory VerifierARCHIVED FILE
tools/build_public_manifest.py
3.24 KB · Oct 4, 2026 · 12:29 UTC
#!/usr/bin/env python3
"""Build or verify the exact clean-room public-file allowlist."""
from __future__ import annotations
import argparse
import hashlib
import json
import stat
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUTPUT = ROOT / "PUBLIC_MANIFEST.json"
IGNORED_DIRECTORY_NAMES = {".git"}
def canonical_bytes(value: object) -> bytes:
return (
json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
+ "\n"
).encode("utf-8")
def classification(relative: str) -> str:
if relative.startswith("fixtures/"):
return "synthetic_generator"
if relative.startswith("tests/data/"):
return "synthetic_test_data"
return "new_clean_room"
def is_reparse(path: Path) -> bool:
info = path.lstat()
flag = getattr(stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
return path.is_symlink() or bool(getattr(info, "st_file_attributes", 0) & flag)
def build() -> dict:
files = []
candidates = sorted(
ROOT.rglob("*"),
key=lambda candidate: candidate.relative_to(ROOT).as_posix().encode("utf-8"),
)
for path in candidates:
relative_parts = path.relative_to(ROOT).parts
if any(part in IGNORED_DIRECTORY_NAMES for part in relative_parts):
continue
if is_reparse(path):
raise RuntimeError("reparse points and symbolic links are not publishable")
if path.is_dir():
continue
if not path.is_file():
raise RuntimeError("nonregular entries are not publishable")
if path == OUTPUT:
continue
path.resolve(strict=True).relative_to(ROOT.resolve(strict=True))
relative = path.relative_to(ROOT).as_posix()
if "__pycache__" in path.parts:
raise RuntimeError("generated cache is not publishable")
data = path.read_bytes()
files.append(
{
"path": relative,
"bytes": len(data),
"sha256": hashlib.sha256(data).hexdigest(),
"origin": classification(relative),
}
)
return {
"format_version": "1.0",
"self_excluded": "PUBLIC_MANIFEST.json",
"release_status": "candidate_licensed_not_published",
"files": files,
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--check", action="store_true")
args = parser.parse_args()
expected = canonical_bytes(build())
if args.check:
actual = OUTPUT.read_bytes() if OUTPUT.is_file() else b""
status = "PASS" if actual == expected else "FAIL"
print(
json.dumps(
{
"status": status,
"file_count": len(json.loads(expected)["files"]),
},
sort_keys=True,
separators=(",", ":"),
)
)
return 0 if status == "PASS" else 1
OUTPUT.write_bytes(expected)
print(
json.dumps(
{
"status": "GENERATED",
"file_count": len(json.loads(expected)["files"]),
},
sort_keys=True,
separators=(",", ":"),
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
SHA-256: 3d119f12e72a9f03e5516bd5f461e9b8577ee31938d9567ddf833b824e8ca542