Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .github/scripts/test_verify_relink_recovery_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def make_snapshot(path: Path, content: str, context: str = "ספר א") -> None:


class RecoverySnapshotVerifierTest(unittest.TestCase):
def run_case(self, original_content, rebuilt_content, artifact_record=None, rebuilt_context="ספר א"):
def run_case(self, original_content, rebuilt_content, artifact_record=None, rebuilt_context="ספר א",
meta_schema=2, baseline_schema=2):
temporary = tempfile.TemporaryDirectory()
self.addCleanup(temporary.cleanup)
root = Path(temporary.name)
Expand All @@ -53,12 +54,12 @@ def run_case(self, original_content, rebuilt_content, artifact_record=None, rebu
digest = hashlib.sha256(original.read_bytes()).hexdigest()
payload_meta = root / "meta.json"
payload_meta.write_text(
json.dumps({"schema_version": 2, "snapshot": {"sha256": digest}}),
json.dumps({"schema_version": meta_schema, "snapshot": {"sha256": digest}}),
encoding="utf-8",
)
baseline = root / "baseline.json"
baseline.write_text(
json.dumps({"schema_version": 2, "snapshot_sha256": digest}),
json.dumps({"schema_version": baseline_schema, "snapshot_sha256": digest}),
encoding="utf-8",
)
artifacts = root / "artifacts" / "Sefaria"
Expand All @@ -84,6 +85,23 @@ def test_identical_snapshots_pass(self):
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("unlinked_image_src_differences=0", result.stdout)

def test_linker_meta_schema_3_passes(self):
# The Linker writes meta.json schema 3 since a9ae2d4; the snapshot sha
# field it binds is unchanged, so a recovery must still verify.
result = self.run_case("טקסט", "טקסט", meta_schema=3)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("RECOVERY_SNAPSHOT_SEMANTIC_OK", result.stdout)

def test_unknown_linker_meta_schema_fails(self):
result = self.run_case("טקסט", "טקסט", meta_schema=4)
self.assertNotEqual(result.returncode, 0)
self.assertIn("Linker meta schema", result.stderr)

def test_unknown_baseline_schema_fails(self):
result = self.run_case("טקסט", "טקסט", baseline_schema=3)
self.assertNotEqual(result.returncode, 0)
self.assertIn("line baseline schema 2", result.stderr)

def test_unlinked_remote_to_inline_image_passes(self):
inline = base64.b64encode(b"png").decode()
result = self.run_case(
Expand Down
17 changes: 15 additions & 2 deletions .github/scripts/verify_relink_recovery_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
re.IGNORECASE,
)
MAX_IMAGE_BYTES = 5 * 1024 * 1024
PAYLOAD_META_SCHEMAS = frozenset({2, 3})
BASELINE_SCHEMA = 2


def _sha256(path: Path) -> str:
Expand Down Expand Up @@ -116,8 +118,19 @@ def verify(
raise SystemExit("original raw snapshot SHA does not match Linker payload metadata")
if baseline.get("snapshot_sha256") != original_sha:
raise SystemExit("line baseline is not bound to the original raw snapshot")
if meta.get("schema_version") != 2 or baseline.get("schema_version") != 2:
raise SystemExit("recovery snapshot comparison requires schema 2")
# The Linker bumped meta.json to schema 3 in a9ae2d4 (2026-08-31) without
# changing ``snapshot.sha256`` — the only field read here. The line baseline
# manifest is still schema 2 (line_baseline.SCHEMA_VERSION).
if meta.get("schema_version") not in PAYLOAD_META_SCHEMAS:
raise SystemExit(
"recovery snapshot comparison requires Linker meta schema "
f"{sorted(PAYLOAD_META_SCHEMAS)}, got {meta.get('schema_version')!r}"
)
if baseline.get("schema_version") != BASELINE_SCHEMA:
raise SystemExit(
f"recovery snapshot comparison requires line baseline schema {BASELINE_SCHEMA}, "
f"got {baseline.get('schema_version')!r}"
)

connections = []
for path in (original, rebuilt):
Expand Down
Loading