@@ -43,16 +43,14 @@ def test_ambiguous_or_out_of_protocol_recovery_is_rejected(change):
4343 missing_cell (rows , ["a" , "b" , "c" ])
4444
4545
46- def parent_fixture (tmp_path : Path ) -> tuple [Path , Path , Path ]:
46+ def parent_fixture (tmp_path : Path ) -> tuple [Path , Path , Path , str ]:
4747 source_root = tmp_path / "source"
4848 source_root .mkdir ()
4949 (source_root / "executor.py" ).write_text ("value = 1\n " )
5050 parent = tmp_path / "parent"
5151 parent .mkdir ()
5252 protocol = {
53- "source_sha256" : {
54- "executor.py" : digest_bytes ((source_root / "executor.py" ).read_bytes ())
55- }
53+ "source_sha256" : {"executor.py" : digest_bytes ((source_root / "executor.py" ).read_bytes ())}
5654 }
5755 artifacts = {
5856 "protocol.json" : json .dumps (protocol ).encode (),
@@ -71,14 +69,14 @@ def parent_fixture(tmp_path: Path) -> tuple[Path, Path, Path]:
7169 }
7270 )
7371 )
74- return source_root , parent , manifest
72+ return source_root , parent , manifest , digest_bytes ( manifest . read_bytes ())
7573
7674
7775def test_parent_evidence_requires_independent_manifest_and_contained_regular_files (
7876 tmp_path : Path ,
7977) -> None :
80- source_root , parent , manifest = parent_fixture (tmp_path )
81- verified = verify_parent_evidence (parent , manifest , source_root )
78+ source_root , parent , manifest , manifest_digest = parent_fixture (tmp_path )
79+ verified = verify_parent_evidence (parent , manifest , manifest_digest , source_root )
8280 assert set (verified ) == {
8381 "parent_manifest" ,
8482 "protocol.json" ,
@@ -88,23 +86,33 @@ def test_parent_evidence_requires_independent_manifest_and_contained_regular_fil
8886 inside_manifest = parent / "parent-manifest.json"
8987 inside_manifest .write_bytes (manifest .read_bytes ())
9088 with pytest .raises (ValueError , match = "outside the parent artifact directory" ):
91- verify_parent_evidence (parent , inside_manifest , source_root )
89+ verify_parent_evidence (parent , inside_manifest , manifest_digest , source_root )
9290
9391 outside = tmp_path / "outside"
9492 outside .write_text ("forged\n " )
9593 (parent / "results.jsonl" ).unlink ()
9694 (parent / "results.jsonl" ).symlink_to (outside )
9795 with pytest .raises (ValueError , match = "regular file" ):
98- verify_parent_evidence (parent , manifest , source_root )
96+ verify_parent_evidence (parent , manifest , manifest_digest , source_root )
97+
98+
99+ def test_parent_evidence_rejects_manifest_changed_after_digest_is_supplied (
100+ tmp_path : Path ,
101+ ) -> None :
102+ source_root , parent , manifest , manifest_digest = parent_fixture (tmp_path )
103+ manifest .write_text ("{}" )
104+ with pytest .raises (ValueError , match = "independently supplied digest" ):
105+ verify_parent_evidence (parent , manifest , manifest_digest , source_root )
99106
100107
101108def test_parent_source_paths_cannot_escape_source_root (tmp_path : Path ) -> None :
102- source_root , parent , manifest = parent_fixture (tmp_path )
109+ source_root , parent , manifest , _ = parent_fixture (tmp_path )
103110 protocol = json .loads ((parent / "protocol.json" ).read_text ())
104111 protocol ["source_sha256" ] = {"../outside.py" : "0" * 64 }
105112 (parent / "protocol.json" ).write_text (json .dumps (protocol ))
106113 payload = json .loads (manifest .read_text ())
107114 payload ["artifacts" ]["protocol.json" ] = digest_bytes ((parent / "protocol.json" ).read_bytes ())
108115 manifest .write_text (json .dumps (payload ))
116+ manifest_digest = digest_bytes (manifest .read_bytes ())
109117 with pytest .raises (ValueError , match = "contained relative path" ):
110- verify_parent_evidence (parent , manifest , source_root )
118+ verify_parent_evidence (parent , manifest , manifest_digest , source_root )
0 commit comments