| |
| """Negative tamper tests for the offline release verifier.""" |
|
|
| from __future__ import annotations |
|
|
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
| from pathlib import Path |
|
|
|
|
| ROOT = Path(__file__).resolve().parents[1] |
|
|
|
|
| def verify(path: Path, expected: int) -> None: |
| result = subprocess.run( |
| [sys.executable, "scripts/verify_release.py"], |
| cwd=path, |
| text=True, |
| capture_output=True, |
| check=False, |
| ) |
| if result.returncode != expected: |
| raise AssertionError( |
| f"expected verifier exit {expected}, got {result.returncode}: {result.stdout}{result.stderr}" |
| ) |
|
|
|
|
| def copied_candidate(temp_root: Path) -> Path: |
| target = temp_root / "candidate" |
| shutil.copytree(ROOT, target, ignore=shutil.ignore_patterns(".git", "__pycache__")) |
| return target |
|
|
|
|
| def main() -> int: |
| with tempfile.TemporaryDirectory(prefix="l35-verifier-") as directory: |
| temp_root = Path(directory) |
|
|
| clean = copied_candidate(temp_root / "clean") |
| verify(clean, 0) |
|
|
| claim_tamper = copied_candidate(temp_root / "claim-tamper") |
| claims = claim_tamper / "evidence/active_claims.json" |
| claims.write_text(claims.read_text(encoding="utf-8").replace("Theorem 1", "Tampered theorem", 1), encoding="utf-8") |
| verify(claim_tamper, 1) |
|
|
| pin_tamper = copied_candidate(temp_root / "pin-tamper") |
| pins = pin_tamper / "evidence/pins.json" |
| pins.write_text(pins.read_text(encoding="utf-8").replace("af5ab2d6", "bf5ab2d6", 1), encoding="utf-8") |
| verify(pin_tamper, 1) |
|
|
| inventory_tamper = copied_candidate(temp_root / "inventory-tamper") |
| inventory = inventory_tamper / "evidence/repository_tree.json" |
| inventory.write_text(inventory.read_text(encoding="utf-8").replace("README.md", "README-tampered.md", 1), encoding="utf-8") |
| verify(inventory_tamper, 1) |
|
|
| extra_file = copied_candidate(temp_root / "extra-file") |
| (extra_file / "unexpected.txt").write_text("tamper\n", encoding="utf-8") |
| verify(extra_file, 1) |
|
|
| short_page = copied_candidate(temp_root / "short-page") |
| (short_page / "pages/01-overview.md").write_text("too short\n", encoding="utf-8") |
| verify(short_page, 1) |
|
|
| event_handler = copied_candidate(temp_root / "event-handler") |
| index = event_handler / "index.html" |
| index.write_text(index.read_text(encoding="utf-8").replace("<main>", '<main onload="alert(1)">', 1), encoding="utf-8") |
| verify(event_handler, 1) |
|
|
| external_link = copied_candidate(temp_root / "external-link") |
| index = external_link / "index.html" |
| index.write_text(index.read_text(encoding="utf-8").replace("pages/01-overview.md", "https://example.invalid", 1), encoding="utf-8") |
| verify(external_link, 1) |
|
|
| metadata_tamper = copied_candidate(temp_root / "metadata-tamper") |
| readme = metadata_tamper / "README.md" |
| readme.write_text(readme.read_text(encoding="utf-8").replace("paper-l35QweVxgn", "paper-tampered", 1), encoding="utf-8") |
| verify(metadata_tamper, 1) |
|
|
| print("PASS: clean candidate accepted; eight negative tamper tests rejected") |
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| try: |
| raise SystemExit(main()) |
| except AssertionError as error: |
| print(f"FAIL: {error}", file=sys.stderr) |
| raise SystemExit(1) |
|
|