test_canary_verifier.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import pytest
  2. from app.core.mcp.canary import CanaryVerifier
  3. class Plans:
  4. def __init__(self):
  5. self.evidence = {
  6. "candidate_id": "candidate-1",
  7. "execution_id": "execution-1",
  8. "status": "started",
  9. "sample_runs": 0,
  10. }
  11. self.recorded = []
  12. def get_canary_evidence(self, candidate_id):
  13. assert candidate_id == "candidate-1"
  14. return dict(self.evidence)
  15. def record_canary_verification(self, candidate_id, evidence):
  16. self.recorded.append((candidate_id, evidence))
  17. self.evidence = dict(evidence)
  18. return evidence
  19. class Engine:
  20. def __init__(self, state):
  21. self.state = state
  22. def get_execution(self, execution_id):
  23. assert execution_id == "execution-1"
  24. return {
  25. "id": execution_id,
  26. "state": {"current": self.state},
  27. "outputs": {"secret": "must-not-persist"},
  28. }
  29. class Comparator:
  30. def __init__(self, equivalent=True):
  31. self.equivalent = equivalent
  32. def compare(self, baseline_execution_id, candidate_execution_id):
  33. assert baseline_execution_id == "baseline-1"
  34. assert candidate_execution_id == "execution-1"
  35. return {
  36. "equivalent": self.equivalent,
  37. "metrics": {
  38. "row_count_delta": 0,
  39. "duration_delta_seconds": -2,
  40. },
  41. "raw_rows": [{"email": "must-not-persist"}],
  42. }
  43. def test_canary_verifier_records_pass_only_from_successful_engine_and_comparator():
  44. plans = Plans()
  45. verifier = CanaryVerifier(
  46. plans=plans,
  47. engine=Engine("SUCCESS"),
  48. comparator=Comparator(equivalent=True),
  49. )
  50. result = verifier.verify("candidate-1", baseline_execution_id="baseline-1")
  51. assert result["status"] == "passed"
  52. assert result["sample_runs"] == 1
  53. assert result["verified_by"] == "dataops-canary-verifier"
  54. assert result["verification_summary"] == {
  55. "engine_state": "SUCCESS",
  56. "equivalent": True,
  57. "metrics": {
  58. "row_count_delta": 0,
  59. "duration_delta_seconds": -2,
  60. },
  61. }
  62. assert "must-not-persist" not in repr(plans.recorded)
  63. def test_canary_verifier_fails_closed_for_non_terminal_or_non_equivalent_runs():
  64. plans = Plans()
  65. running = CanaryVerifier(plans=plans, engine=Engine("RUNNING"))
  66. result = running.verify("candidate-1")
  67. assert result["status"] == "started"
  68. assert plans.recorded == []
  69. failed = CanaryVerifier(
  70. plans=Plans(),
  71. engine=Engine("SUCCESS"),
  72. comparator=Comparator(equivalent=False),
  73. )
  74. result = failed.verify("candidate-1", baseline_execution_id="baseline-1")
  75. assert result["status"] == "failed"
  76. def test_canary_verifier_rejects_untrusted_preverified_evidence():
  77. plans = Plans()
  78. plans.evidence["status"] = "passed"
  79. verifier = CanaryVerifier(plans=plans, engine=Engine("SUCCESS"))
  80. with pytest.raises(ValueError, match="already finalized"):
  81. verifier.verify("candidate-1")