test_p3_wp14_fresh_verifier.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from __future__ import annotations
  2. import subprocess
  3. import sys
  4. import hashlib
  5. from datetime import datetime, timezone
  6. from pathlib import Path
  7. import pytest
  8. ROOT = Path(__file__).resolve().parents[1]
  9. sys.path.insert(0, str(ROOT / "scripts"))
  10. def test_fresh_verifier_runs_generator_before_reading_unsigned_cache(monkeypatch) -> None:
  11. import verify_p3_wp14_fresh_local_engineering as verifier
  12. calls: list[str] = []
  13. monkeypatch.setattr(verifier, "_run_generator", lambda: calls.append("generator") or "fresh-nonce")
  14. monkeypatch.setattr(verifier, "_verify_cache", lambda _now, **_kwargs: calls.append("verify"))
  15. assert verifier.main() == 0
  16. assert calls == ["generator", "verify"]
  17. def test_tampered_cache_is_rebuilt_before_fresh_verification(monkeypatch) -> None:
  18. import verify_p3_wp14_fresh_local_engineering as verifier
  19. cache = {"digest": "tampered"}
  20. def rebuild() -> str:
  21. cache["digest"] = "fresh"
  22. return "fresh-nonce"
  23. def verify(_now, **_kwargs) -> None:
  24. assert cache["digest"] == "fresh"
  25. monkeypatch.setattr(verifier, "_run_generator", rebuild)
  26. monkeypatch.setattr(verifier, "_verify_cache", verify)
  27. assert verifier.main() == 0
  28. def test_fresh_verifier_rejects_expired_cache_without_a_new_generator_run() -> None:
  29. import verify_p3_wp14_fresh_local_engineering as verifier
  30. with pytest.raises(ValueError, match="expired"):
  31. verifier._assert_current_expiry(
  32. {"expires_at": "2000-01-01T00:00:00Z"}, datetime.now(timezone.utc)
  33. )
  34. def test_fresh_verifier_timeout_returns_failure(monkeypatch) -> None:
  35. import verify_p3_wp14_fresh_local_engineering as verifier
  36. def timeout() -> None:
  37. raise subprocess.TimeoutExpired(["python", "generator"], verifier.GENERATOR_TIMEOUT_SECONDS)
  38. monkeypatch.setattr(verifier, "_run_generator", timeout)
  39. assert verifier.main() == 1
  40. def test_verify_existing_is_read_only_and_never_runs_generator(monkeypatch, capsys) -> None:
  41. import verify_p3_wp14_fresh_local_engineering as verifier
  42. calls: list[str] = []
  43. monkeypatch.setattr(verifier, "_run_generator", lambda: calls.append("generator"))
  44. monkeypatch.setattr(verifier, "_verify_cache", lambda _now, **_kwargs: calls.append("verify"))
  45. assert verifier.main(["--verify-existing"]) == 0
  46. assert calls == ["verify"]
  47. assert "VERIFY_EXISTING_DIAGNOSTIC_ONLY" in capsys.readouterr().out
  48. def test_verify_existing_preserves_existing_cache_mtime_and_digest(monkeypatch, tmp_path: Path) -> None:
  49. import verify_p3_wp14_fresh_local_engineering as verifier
  50. cache = tmp_path / "unsigned-cache.json"
  51. cache.write_bytes(b'{"cache":"existing"}\n')
  52. before = (cache.stat().st_mtime_ns, hashlib.sha256(cache.read_bytes()).hexdigest())
  53. monkeypatch.setattr(verifier, "_run_generator", lambda: pytest.fail("must remain read-only"))
  54. monkeypatch.setattr(verifier, "_verify_cache", lambda _now, **_kwargs: cache.read_bytes())
  55. assert verifier.main(["--verify-existing"]) == 0
  56. after = (cache.stat().st_mtime_ns, hashlib.sha256(cache.read_bytes()).hexdigest())
  57. assert after == before
  58. def test_fresh_generator_environment_drops_parent_sensitive_overrides(monkeypatch) -> None:
  59. import verify_p3_wp14_fresh_local_engineering as verifier
  60. monkeypatch.setenv("HOME", "/attacker")
  61. monkeypatch.setenv("DOCKER_CONFIG", "/attacker/docker")
  62. monkeypatch.setenv("GIT_DIR", "/attacker/git")
  63. env = verifier._minimal_command_env()
  64. assert env["HOME"] == str(verifier.COMMAND_HOME)
  65. assert env["DOCKER_CONFIG"] == str(verifier.COMMAND_HOME / "docker")
  66. assert "GIT_DIR" not in env
  67. assert "TMPDIR" in env and {key for key in env if key.startswith("PYTHON")} == {"PYTHONDONTWRITEBYTECODE"}
  68. assert "DOCKER_HOST" not in env and "DOCKER_CONTEXT" not in env
  69. def test_ledger_command_environment_drops_parent_sensitive_overrides(monkeypatch) -> None:
  70. import generate_p3_wp14_verification_ledger as ledger
  71. monkeypatch.setenv("HOME", "/attacker")
  72. monkeypatch.setenv("TMPDIR", "/attacker/tmp")
  73. monkeypatch.setenv("PYTHONPATH", "/attacker/python")
  74. monkeypatch.setenv("GIT_DIR", "/attacker/git")
  75. monkeypatch.setenv("COMPOSE_FILE", "/attacker/compose.yml")
  76. monkeypatch.setenv("DOCKER_CONFIG", "/attacker/docker")
  77. monkeypatch.setenv("DOCKER_HOST", "unix:///attacker.sock")
  78. env = ledger._minimal_command_env()
  79. assert env["HOME"] == str(ledger.COMMAND_HOME)
  80. assert env["TMPDIR"] == str(ledger.COMMAND_HOME / "tmp")
  81. assert env["DOCKER_CONFIG"] == str(ledger.COMMAND_HOME / "docker")
  82. assert "GIT_DIR" not in env and "COMPOSE_FILE" not in env and "DOCKER_HOST" not in env