|
1 | 1 | """A checklist label cannot bypass missing, stale or contradictory evidence.""" |
2 | 2 | import hashlib |
| 3 | +import importlib.util |
3 | 4 | import json |
| 5 | +import py_compile |
4 | 6 | import subprocess |
5 | 7 |
|
6 | 8 | import pytest |
@@ -271,6 +273,54 @@ def test_ignored_executable_artifact_cannot_qualify_candidate(ledger, tmp_path): |
271 | 273 | assert not result["valid"] |
272 | 274 |
|
273 | 275 |
|
| 276 | +def test_ignored_importable_source_cannot_qualify_candidate(ledger, tmp_path): |
| 277 | + repository = tmp_path / "ignored-source-repo" |
| 278 | + repository.mkdir() |
| 279 | + (repository / ".gitignore").write_text("sitecustomize.py\n", encoding="utf-8") |
| 280 | + (repository / "engine.py").write_text("original", encoding="utf-8") |
| 281 | + subprocess.run(["git", "init", "--quiet", str(repository)], check=True) |
| 282 | + subprocess.run(["git", "add", ".gitignore", "engine.py"], cwd=repository, check=True) |
| 283 | + subprocess.run(["git", "-c", "user.name=Fixture", "-c", "user.email=fixture@example.invalid", |
| 284 | + "commit", "--quiet", "-m", "fixture"], cwd=repository, check=True) |
| 285 | + ledger["components"]["engine"]["commit"] = subprocess.check_output( |
| 286 | + ["git", "rev-parse", "HEAD"], cwd=repository, text=True).strip() |
| 287 | + ledger["candidate_id"] = candidate_id(ledger["components"]) |
| 288 | + for name in RELEASE_GATES: |
| 289 | + pass_gate(ledger, tmp_path, name) |
| 290 | + (repository / "sitecustomize.py").write_text("raise RuntimeError('ignored')\n", encoding="utf-8") |
| 291 | + result = validate(ledger, tmp_path, engine_root=repository) |
| 292 | + assert not result["engine_checkout_verified"] |
| 293 | + assert any("sitecustomize.py" in error for error in result["errors"]) |
| 294 | + assert not result["valid"] |
| 295 | + |
| 296 | + |
| 297 | +def test_unchecked_hash_bytecode_cannot_qualify_candidate(ledger, tmp_path): |
| 298 | + repository = tmp_path / "unchecked-bytecode-repo" |
| 299 | + repository.mkdir() |
| 300 | + (repository / ".gitignore").write_text("__pycache__/\n", encoding="utf-8") |
| 301 | + source = repository / "engine.py" |
| 302 | + source.write_text("value = 'tracked'\n", encoding="utf-8") |
| 303 | + subprocess.run(["git", "init", "--quiet", str(repository)], check=True) |
| 304 | + subprocess.run(["git", "add", ".gitignore", "engine.py"], cwd=repository, check=True) |
| 305 | + subprocess.run(["git", "-c", "user.name=Fixture", "-c", "user.email=fixture@example.invalid", |
| 306 | + "commit", "--quiet", "-m", "fixture"], cwd=repository, check=True) |
| 307 | + ledger["components"]["engine"]["commit"] = subprocess.check_output( |
| 308 | + ["git", "rev-parse", "HEAD"], cwd=repository, text=True).strip() |
| 309 | + ledger["candidate_id"] = candidate_id(ledger["components"]) |
| 310 | + for name in RELEASE_GATES: |
| 311 | + pass_gate(ledger, tmp_path, name) |
| 312 | + py_compile.compile( |
| 313 | + str(source), |
| 314 | + cfile=importlib.util.cache_from_source(str(source)), |
| 315 | + doraise=True, |
| 316 | + invalidation_mode=py_compile.PycInvalidationMode.UNCHECKED_HASH, |
| 317 | + ) |
| 318 | + result = validate(ledger, tmp_path, engine_root=repository) |
| 319 | + assert not result["engine_checkout_verified"] |
| 320 | + assert any("__pycache__" in error for error in result["errors"]) |
| 321 | + assert not result["valid"] |
| 322 | + |
| 323 | + |
274 | 324 | @pytest.mark.parametrize("flag", ["--assume-unchanged", "--skip-worktree"]) |
275 | 325 | def test_hidden_git_changes_cannot_qualify_candidate(ledger, tmp_path, flag): |
276 | 326 | repository = tmp_path / "hidden-repo" |
|
0 commit comments