L1: the integrity check reads the scroll (tablet 38)
L1Reader.verify_integrity/0 read the hash stored in integrity.sha256
and compared that string with the hash compiled into the module. It
never opened a verse. On that comparison of a constant with its own
copy rested `l1_hash: pass`, the Cloud's "L1 corrupted — the cloud is
not visible", and Construction §1.2. A changed verse would have passed
every one of them. Every existing test passed too, because every test
asked about an untouched L1.
- L1Reader.compute_tree_hash/1: SHA-256 over every file under torah/ —
relative path, then bytes — in the order scripts/build_l1.py hashed
them (directories by path, files by name, plain string order). On the
real L1 it yields the pinned 156b1d27…; for a tampered copy it yields
the same hash the Python implementation does.
- VavPipeline.L1Integrity (new, supervised): reads and hashes the scroll
when the pipeline starts (~0.9 s in the image) and again every ten
minutes; logs and signals the assembly when the answer changes.
- verify_integrity/0 now requires BOTH: the recorded hash is the pinned
one, AND the scroll on disk hashes to it (answered from the witness's
last reading; computed on the spot where the witness is not running).
Callers are unchanged — the Shema context, the health check and the
status endpoint all inherit the real check.
- scripts/verify_l1.py: the same reading by hand. KOHEN.md and
KOHEN_PROMPT.md used the hollow comparison as their L1 gate; they now
run this.
- test/tablet38_l1_integrity_test.exs — 9 tests: the hash and its
order; one byte / one added file / one rename each change it; the
witness; and the whole path — with an altered scroll and an untouched
integrity.sha256, verify_integrity fails, health says l1_hash: fail,
and /peah/ask does not answer.
Specs: architecture §2.2 (which had been made to confess the hollow
check in d7520cd) and Construction §1.2 now describe the real one — and
its limit: a change is noticed within ten minutes, not at the instant.
deploy/ARCHITECTURE.md likewise. Doorpost @expected_hash 7e5286b9… →
3f6d47a0…, in this commit, with the witnessed files that moved it
(architecture, vayakhel).
Read before committing: Elixir 483/0 on seeds 0 7 42 99 191243. The
built image, run twice: on the engraved scroll — "read and matches
(928ms)", l1_hash pass, /peah/ask 200; on a copy with ONE LETTER changed
in Bereishit 1:1 and integrity.sha256 untouched — L1_INTEGRITY_FAILED,
l1_hash fail, cloud not readable, /peah/ask 503.
Not done: the Haskell side. Luchot.Firmware.l1ExpectedHash is compared
with nothing; the engine reads L1 without hashing it (that would need a
SHA-256 dependency). The engine is reached only through the pipeline,
which now gates every cycle on the real check.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
d7520cd69d
commit
bbe2c4b7ba
11 files changed
+579
-17
No files matched your search
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Read the scroll and say whether it is the scroll that was engraved.
|
||||
|
||||
Hashes every file under l1/torah — path, then bytes, in the order
|
||||
build_l1.py hashed them — and compares the result with the hash recorded
|
||||
in l1/integrity.sha256 (and with an expected hash, if one is given).
|
||||
|
||||
Comparing integrity.sha256 with a constant proves only that the two
|
||||
copies of the constant agree. This reads the verses.
|
||||
|
||||
Usage:
|
||||
scripts/verify_l1.py # l1/ beside this script's repo
|
||||
scripts/verify_l1.py /mnt/torah # another L1 root
|
||||
scripts/verify_l1.py l1 <sha256> # also require this exact hash
|
||||
|
||||
Exit status 0 if everything agrees, 1 if anything does not.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from build_l1 import generate_integrity_hash # noqa: E402
|
||||
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
repo_root = Path(__file__).resolve().parent.parent
|
||||
l1_root = Path(argv[1]) if len(argv) > 1 else repo_root / "l1"
|
||||
expected = argv[2].strip().lower() if len(argv) > 2 else None
|
||||
|
||||
torah = l1_root / "torah"
|
||||
if not torah.is_dir():
|
||||
print(f"FAIL: {torah} is not a directory")
|
||||
return 1
|
||||
|
||||
computed = generate_integrity_hash(str(torah))
|
||||
print(f"computed {computed}")
|
||||
|
||||
ok = True
|
||||
record = l1_root / "integrity.sha256"
|
||||
if record.is_file():
|
||||
recorded = record.read_text().strip()
|
||||
print(f"recorded {recorded}")
|
||||
ok = ok and recorded == computed
|
||||
else:
|
||||
print(f"recorded (no {record})")
|
||||
ok = False
|
||||
|
||||
if expected is not None:
|
||||
print(f"expected {expected}")
|
||||
ok = ok and expected == computed
|
||||
|
||||
print("OK: the scroll matches" if ok else "FAIL: the scroll does not match")
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv))
|
||||
Reference in new issue
Block a user