test: tighten historical-pin checks per review of 941eb28b
- test_refined_dfg::test_source_pin runs its mismatch negative controls first (now including window mode) so missing history cannot skip them. - test_re100: renamed to test_manifest_matches_its_pinned_commit, plus an explicit record that today's src differs from the pin. - Structural manifest checks run before any history-dependent check. - Real tamper test: a flipped digest raises via verify_manifest, and a path absent at the commit raises ValueError. - A blobless clone (tree present, blob missing) is reported as unavailable history, not as a missing path. - All history skips go through history_unavailable(): fatal when CELERIS_REQUIRE_HISTORY=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f02355a2b7
commit
8064834c37
6 files changed
+72
-37
No files matched your search
@@ -10,7 +10,8 @@ ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT / "tests/validation"))
|
||||
import pytest
|
||||
from source_provenance import (HistoryUnavailable, checkout_provenance, historical_sha256,
|
||||
historical_tree)
|
||||
historical_tree, history_unavailable, verify_manifest)
|
||||
import unittest
|
||||
import re100_helpers
|
||||
import run_jet_circle_cv
|
||||
|
||||
@@ -19,10 +20,7 @@ ORIGIN = "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5"
|
||||
|
||||
def test_manifests_match_their_recorded_source_and_preserve_origin():
|
||||
"""Historical evidence integrity: each manifest describes the tree of its own commit."""
|
||||
try:
|
||||
names = historical_tree(ROOT, ORIGIN)
|
||||
except HistoryUnavailable as error:
|
||||
pytest.skip(f"historical integrity NOT checked: {error}")
|
||||
manifests = []
|
||||
for group, hashes_key, revision_key in (
|
||||
("dfg_re100", "production_sha256", "commit"),
|
||||
("jet_circle_cv", "files", "revision"),
|
||||
@@ -32,15 +30,22 @@ def test_manifests_match_their_recorded_source_and_preserve_origin():
|
||||
ROOT / "tests/validation/data" / group / "source_manifest.json"
|
||||
).read_text()
|
||||
)
|
||||
# Structural checks need no history and always run.
|
||||
assert manifest[revision_key] == ORIGIN
|
||||
assert set(manifest[hashes_key]) == set(names)
|
||||
assert manifest["source_origin_commits"][-1] == ORIGIN
|
||||
assert (
|
||||
manifest["historical_checkpoints"]["production"]
|
||||
== "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2"
|
||||
)
|
||||
assert "not inherited from d79" in manifest["experiment"]
|
||||
assert historical_sha256(ROOT, ORIGIN, manifest[hashes_key]) == manifest[hashes_key]
|
||||
manifests.append(manifest[hashes_key])
|
||||
try:
|
||||
names = historical_tree(ROOT, ORIGIN)
|
||||
for digests in manifests:
|
||||
assert set(digests) == set(names)
|
||||
verify_manifest(ROOT, ORIGIN, digests)
|
||||
except HistoryUnavailable as error:
|
||||
history_unavailable(unittest.TestCase(), error)
|
||||
assert re100_helpers.PIN == run_jet_circle_cv.PIN == ORIGIN
|
||||
|
||||
|
||||
@@ -82,9 +87,14 @@ def test_historical_check_rejects_tampering_and_reports_missing_history(tmp_path
|
||||
historical_sha256(ROOT, "0" * 40, ["src/x.py"]) # commit absent
|
||||
manifest = json.loads(
|
||||
(ROOT / "tests/validation/data/dfg_re100/source_manifest.json").read_text())
|
||||
name = sorted(manifest["production_sha256"])[0]
|
||||
digests = dict(manifest["production_sha256"])
|
||||
name = sorted(digests)[0]
|
||||
tampered = dict(digests, **{name: ("0" if digests[name][0] != "0" else "1") + digests[name][1:]})
|
||||
try:
|
||||
actual = historical_sha256(ROOT, ORIGIN, [name])
|
||||
historical_tree(ROOT, ORIGIN)
|
||||
except HistoryUnavailable as error:
|
||||
pytest.skip(f"historical integrity NOT checked: {error}")
|
||||
assert actual != {name: "0" * 64} # a tampered digest would not match
|
||||
history_unavailable(unittest.TestCase(), error)
|
||||
with pytest.raises(RuntimeError, match="Historical manifest mismatch"):
|
||||
verify_manifest(ROOT, ORIGIN, tampered) # one flipped digest is caught
|
||||
with pytest.raises(ValueError, match="not part of"):
|
||||
historical_sha256(ROOT, ORIGIN, ["src/CelerisLab/does_not_exist.py"])
|
||||
Reference in new issue
Block a user