"""Server wiring for the #260 loop driver (track 2, module level). Uses a real #241/#247 chain (LedgerStore on a temp file) and a real sqlite loop-state connection -- no production tasks, no GitHub, no production DB. The one fake is FailingLedgerStore, used only to prove ledger-failure fail-closed behaviour. """ import os import sqlite3 import sys import tempfile import unittest from pathlib import Path try: from cloud import audit_loop_wiring as wiring from cloud.audit_wiring import pushback_block_for_task from cloud.ledger import LedgerStore from cloud.ledger import verify_chain except ImportError: sys.path.insert(0, str(Path(__file__).resolve().parents[2])) from cloud import audit_loop_wiring as wiring from cloud.audit_wiring import pushback_block_for_task from cloud.ledger import LedgerStore from cloud.ledger import verify_chain MODULE = "mod-a" VERSION = "v1" OLD_REF = {"archive_ref": "task:parent:pre-rebuild"} EXTRA_PASS = { "security_unconditional": True, "regression_exact_artifact": True, "demo_runnable": True, "known_deviation_due_todo": True, "audit_signer_separation": True, "qa_failed_links_rerun": True, } HARD_PASS = { "files_changed": ["apps/web/a.py"], "owned_dir": "apps/web", "protection": "protected", "ci_status": "success", "ci_checks": [{"name": "ci", "status": "success"}], "required_checks": ["ci"], "contract_version": "v1", "contract_frozen": True, "coordinator_approved": True, "unresolved_review_comments": 0, } def fail_verdict(text="check x failed", source="audit", **extra): verdict = { "verdict": "fail", "source": source, "verdict_text": text, "failures": [{"check": "ci_green", "detail": text}], "passed_items": ["a", "b", "c"], "contract_version": VERSION, } verdict.update(extra) return verdict def pass_verdict(**extra): verdict = { "verdict": "pass", "source": "audit", "verdict_text": "all green", "failures": [], "passed_items": ["a", "b", "c"], "contract_version": VERSION, } verdict.update(extra) return verdict class FailingLedgerStore: """Every append raises: proves the wiring never saves state after a ledger failure.""" def __getattr__(self, name): if name.startswith("append_"): def _raise(*args, **kwargs): raise RuntimeError("ledger down") return _raise raise AttributeError(name) class WiringTestCase(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.ledger_path = os.path.join(self.tmp.name, "ledger.db") self.store = LedgerStore(self.ledger_path) self.conn = sqlite3.connect(":memory:") self.task = {"id": "task-parent", "project_id": "proj-1", "module_id": MODULE, "contract_version": VERSION} def tearDown(self): try: self.store.close() except Exception: pass self.conn.close() self.tmp.cleanup() def _block(self, task_id="task-parent"): return pushback_block_for_task(self.store.conn, task_id) def _verdict(self, verdict, **kwargs): kwargs.setdefault("user_id", "auditor-1") return wiring.process_audit_verdict( self.conn, self.store, self.task, verdict, **kwargs) def test_module_mapping_explicit_wins_and_fallback_is_task_id(self): self.assertEqual( wiring.resolve_module_id( {"id": "t1", "module_id": "m-explicit"}), "m-explicit") self.assertEqual( wiring.resolve_module_id({"id": "t1"}), "t1") self.assertEqual( wiring.resolve_module_id({"id": "t1", "module": "m2"}), "m2") with self.assertRaises(ValueError): wiring.resolve_contract_version({"id": "t1"}, None) self.assertEqual( wiring.resolve_contract_version( {"id": "t1"}, {"contract_version": "v9"}), "v9") def test_state_persists_and_reloads_from_table_not_memory(self): result = self._verdict(fail_verdict()) self.assertEqual(result["action_kind"], "pushback") self.assertEqual(result["subtask"]["kind"], "fix") self.assertTrue(result["merge_blocked"]) reloaded = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(reloaded.pushback_round, 1) self.assertEqual(reloaded.failure_count, 1) self.assertEqual(reloaded.status, "pushback") self.assertTrue(self._block()["merge_blocked"]) # The chain itself verifies: the wiring wrote real rows. self.assertTrue(verify_chain(self.store.conn)["ok"]) def test_full_chain_fail_fix_reaudit_pass_unblocks(self): first = self._verdict(fail_verdict()) fix_task = {"id": "task-fix-1", "project_id": "proj-1", "module_id": MODULE, "contract_version": VERSION} result = wiring.process_fix_completion( self.conn, self.store, fix_task, {"reaudit_verdict": pass_verdict()}, automated={"hard_gate": HARD_PASS, "extra_checks": EXTRA_PASS}, user_id="auditor-1", ledger_task_id="task-parent") self.assertEqual(result["action_kind"], "pass") self.assertIsNone(result["subtask"]) self.assertFalse(result["merge_blocked"]) self.assertTrue( result["automated_checks"]["automated_checks_pass"]) # Parent task dict untouched by the wiring layer: the # original task is never rolled back by this module. self.assertNotIn("status", self.task) self.assertFalse(self._block()["merge_blocked"]) state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.status, "passed") self.assertEqual(state.failure_count, 0) def test_automated_failure_forces_claimed_pass_to_fail(self): self._verdict(fail_verdict()) fix_task = {"id": "task-fix-1", "project_id": "proj-1", "module_id": MODULE, "contract_version": VERSION} broken_extra = dict(EXTRA_PASS, demo_runnable=False) result = wiring.process_fix_completion( self.conn, self.store, fix_task, {"reaudit_verdict": pass_verdict()}, automated={"hard_gate": HARD_PASS, "extra_checks": broken_extra}, user_id="auditor-1", ledger_task_id="task-parent") # Automated checks passing is never audit passing, and # here they did not pass: the claimed pass is forced fail. self.assertEqual(result["action_kind"], "pushback") self.assertTrue(result["merge_blocked"]) self.assertIn("demo_runnable", result["automated_checks"]["failed_checks"]) self.assertTrue(self._block()["merge_blocked"]) def test_fix_without_reaudit_verdict_and_diff_only_refused(self): self._verdict(fail_verdict()) fix_task = {"id": "task-fix-1", "project_id": "proj-1", "module_id": MODULE, "contract_version": VERSION} with self.assertRaises(ValueError): wiring.process_fix_completion( self.conn, self.store, fix_task, {"fix_diff": {}}, user_id="auditor-1", ledger_task_id="task-parent") with self.assertRaises(ValueError): wiring.process_fix_completion( self.conn, self.store, fix_task, {"diff_only": True, "reaudit_verdict": pass_verdict()}, user_id="auditor-1", ledger_task_id="task-parent") # Fix with no prior loop at all is refused, not invented. fresh_conn = sqlite3.connect(":memory:") try: with self.assertRaises(ValueError): wiring.process_fix_completion( fresh_conn, self.store, fix_task, {"reaudit_verdict": pass_verdict()}, user_id="auditor-1", ledger_task_id="task-parent") finally: fresh_conn.close() def test_exactly_three_pushes_back_fourth_rebuilds(self): for _ in range(3): result = self._verdict(fail_verdict()) self.assertEqual(result["action_kind"], "pushback") # Fourth failure without a caller-supplied old impl ref # is refused BEFORE any ledger row: state stays at 3. with self.assertRaises(ValueError): self._verdict(fail_verdict()) state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.pushback_round, 3) self.assertEqual(state.failure_count, 3) result = self._verdict(fail_verdict(), old_impl_ref=OLD_REF) self.assertEqual(result["action_kind"], "rebuild") self.assertEqual(result["subtask"]["kind"], "rebuild") state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.rebuild_no, 1) self.assertEqual(state.status, "rebuilding") def test_targeted_third_round_scope(self): self._verdict(fail_verdict()) self._verdict(fail_verdict()) result = self._verdict(fail_verdict( failures=[{"check": "ci_green", "detail": "one left"}], passed_items=["a", "b", "c"], broken_passed_items=[])) self.assertEqual(result["action_kind"], "pushback") self.assertEqual(result["subtask"]["scope"], "targeted") self.assertEqual(result["subtask"]["targeted_items"], ["ci_green"]) def test_correction_to_pass_does_not_unblock(self): self._verdict(fail_verdict()) verdict_rows = self.store.conn.execute( "SELECT id FROM audit_ledger WHERE action = ?" " ORDER BY id ASC", ("audit_verdict",)).fetchall() entry_id = verdict_rows[0][0] result = wiring.process_correction( self.conn, self.store, self.task, {"original_verdict": "fail", "corrected_verdict": "pass", "reviewer": "reviewer-1", "original_entry_id": entry_id, "findings": ["misjudged"], "contract_version": VERSION}, user_id="reviewer-1", ledger_task_id="task-parent") self.assertEqual(result["correction_action"], "schedule_reaudit") self.assertTrue(result["merge_blocked"]) self.assertEqual(result["next_state"].failure_count, 0) self.assertEqual(result["next_state"].status, "blocked") self.assertEqual(result["subtask"]["kind"], "reaudit") # Counting view (0) vs gate view (still blocked) is the # #247 intended divergence, pinned here, not papered over. self.assertTrue(self._block()["merge_blocked"]) # Only a fresh passing verdict unblocks. self._verdict(pass_verdict()) self.assertFalse(self._block()["merge_blocked"]) def test_correction_to_fail_reblocks_at_once(self): self._verdict(pass_verdict()) self.assertFalse(self._block()["merge_blocked"]) verdict_rows = self.store.conn.execute( "SELECT id FROM audit_ledger WHERE action = ?" " ORDER BY id ASC", ("audit_verdict",)).fetchall() entry_id = verdict_rows[-1][0] result = wiring.process_correction( self.conn, self.store, self.task, {"original_verdict": "pass", "corrected_verdict": "fail", "reviewer": "reviewer-1", "original_entry_id": entry_id, "findings": ["missed failure"], "contract_version": VERSION}, user_id="reviewer-1", ledger_task_id="task-parent") self.assertEqual( result["correction_action"], "retrigger_pushback_and_reblock") self.assertTrue(result["merge_blocked"]) self.assertEqual(result["next_state"].failure_count, 1) self.assertTrue(self._block()["merge_blocked"]) def test_acceptance_rebuild_pending_confirm_reject_no_budget(self): for _ in range(4): result = self._verdict( fail_verdict(source="acceptance")) self.assertEqual(result["action_kind"], "pending_user_confirmation") self.assertIsNone(result["subtask"]) self.assertIsNotNone(result["notification"]) state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertTrue(state.pending_confirmation) self.assertEqual(state.rebuild_no, 0) # System/coordinator markers can never confirm. with self.assertRaises(ValueError): wiring.process_rebuild_confirmation( self.conn, self.store, self.task, user_confirmed=True, confirmed_by="system", user_id="user-1", ledger_task_id="task-parent") with self.assertRaises(ValueError): wiring.process_rebuild_confirmation( self.conn, self.store, self.task, user_confirmed=True, confirmed_by="coordinator", user_id="user-1", ledger_task_id="task-parent") # Rejection escalates and consumes no rebuild budget. rejected = wiring.process_rebuild_confirmation( self.conn, self.store, self.task, user_confirmed=False, confirmed_by="user-1", user_id="user-1", ledger_task_id="task-parent") self.assertEqual(rejected["action_kind"], "escalate") state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.rebuild_no, 0) def test_acceptance_rebuild_confirm_then_rebuilds(self): for _ in range(4): self._verdict(fail_verdict(source="acceptance")) confirmed = wiring.process_rebuild_confirmation( self.conn, self.store, self.task, user_confirmed=True, confirmed_by="user-1", old_impl_ref=OLD_REF, user_id="user-1", ledger_task_id="task-parent") self.assertEqual(confirmed["action_kind"], "rebuild") self.assertEqual(confirmed["subtask"]["kind"], "rebuild") state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.rebuild_no, 1) self.assertEqual(state.status, "rebuilding") # Confirming again with no pending confirmation fails. with self.assertRaises(ValueError): wiring.process_rebuild_confirmation( self.conn, self.store, self.task, user_confirmed=True, confirmed_by="user-1", user_id="user-1", ledger_task_id="task-parent") def test_quota_blocked_consumes_nothing(self): self._verdict(fail_verdict()) blocked = self._verdict( fail_verdict(), quota_check=lambda estimate: False) self.assertEqual(blocked["action_kind"], "quota_blocked") self.assertFalse(blocked["state_saved"]) state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.pushback_round, 1) self.assertEqual(state.failure_count, 1) def _raising(estimate): raise RuntimeError("quota service down") blocked2 = self._verdict( fail_verdict(), quota_check=_raising) self.assertEqual(blocked2["action_kind"], "quota_blocked") state = wiring.load_loop_state(self.conn, MODULE, VERSION) self.assertEqual(state.pushback_round, 1) def test_quota_adapter_matches_server_rule(self): check = wiring.build_quota_check(1000000, 999999) self.assertTrue(check(None)) self.assertFalse(check(0.01)) self.assertTrue(wiring.build_quota_check(None, 10 ** 9)(100.0)) def test_cost_threshold_escalates_rebuild_with_full_history(self): for _ in range(3): self._verdict(fail_verdict()) result = self._verdict( fail_verdict(cost_estimate=100.0), cost_threshold=10.0, old_impl_ref=OLD_REF) self.assertEqual(result["action_kind"], "escalate") self.assertEqual(result["notification"]["party"], "user") self.assertEqual( len(result["notification"]["escalation_history"]), 4) self.assertFalse( result["escalation_grants_user_acceptance"]) def test_ledger_failure_fail_closed_state_not_saved(self): failing = FailingLedgerStore() with self.assertRaises(RuntimeError): wiring.process_audit_verdict( self.conn, failing, self.task, fail_verdict(), user_id="auditor-1") self.assertIsNone( wiring.load_loop_state(self.conn, MODULE, VERSION)) def test_automated_reaudit_evidence_missing_fails(self): result = wiring.evaluate_automated_reaudit(None, {}) self.assertFalse(result["automated_checks_pass"]) self.assertIn("hard_gate_evidence_missing", result["failed_checks"]) result = wiring.evaluate_automated_reaudit( HARD_PASS, EXTRA_PASS) self.assertTrue(result["automated_checks_pass"]) # Merge-body vocabulary is translated, not rejected: # branch_protection -> the hard gate's protection. body_style = dict(HARD_PASS) body_style["branch_protection"] = body_style.pop("protection") result = wiring.evaluate_automated_reaudit( body_style, EXTRA_PASS) self.assertTrue(result["automated_checks_pass"]) def test_release_gate_multi_source_and_read_only(self): self._verdict(fail_verdict()) before = self.store.conn.execute( "SELECT COUNT(*) FROM audit_ledger").fetchone()[0] decision = wiring.evaluate_release_gate( "task-parent", self.store.conn, task_status="completed", hard_gate={"allowed": False, "blocks": ["ci_not_green"]}) self.assertFalse(decision["allowed"]) self.assertEqual(decision["http_status"], 409) self.assertEqual(decision["blocked_sources"], ["task_status", "hard_gate", "audit_pushback"]) self.assertEqual(decision["code"], "release_requires_merged") after = self.store.conn.execute( "SELECT COUNT(*) FROM audit_ledger").fetchone()[0] self.assertEqual(before, after) self.assertTrue(verify_chain(self.store.conn)["ok"]) def test_release_gate_evidence_missing_and_allowed(self): decision = wiring.evaluate_release_gate( "task-parent", self.store.conn, task_status="merged", hard_gate=None) self.assertEqual(decision["code"], "release_hard_gate_evidence_missing") decision = wiring.evaluate_release_gate( "task-parent", self.store.conn, task_status="merged", hard_gate={"allowed": True, "blocks": []}) self.assertTrue(decision["allowed"]) self.assertEqual(decision["code"], "release_allowed") def test_release_gate_chain_read_failure_fail_closed(self): closed = sqlite3.connect(":memory:") closed.close() decision = wiring.evaluate_release_gate( "task-parent", closed, task_status="merged", hard_gate={"allowed": True, "blocks": []}) self.assertFalse(decision["allowed"]) self.assertEqual( decision["code"], "release_blocked_state_unavailable") if __name__ == "__main__": unittest.main()