File size: 3,415 Bytes
d38b5af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e32f3c6
 
 
 
 
 
d38b5af
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python3
"""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)