"""Unit tests for scripts/approve_proposal.py.""" from __future__ import annotations import sys from pathlib import Path try: import pytest except ImportError: # standalone fallback so the file runs without pytest installed import contextlib import types pytest = types.SimpleNamespace() @contextlib.contextmanager def _raises(exc, match=None): try: yield except exc as err: if match is not None and match not in str(err): raise AssertionError(f"expected {match!r} in {err!r}") from err return raise AssertionError(f"expected {exc.__name__} to be raised") pytest.raises = _raises REPO_ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(REPO_ROOT / "scripts")) import approve_proposal as approve # noqa: E402 def _strict_pending(): return { "id": "00957f6c-9883-4015-95a4-6b09367efb0e", "proposal_type": "add_edge", "status": "pending_review", "payload": { "apply_payload": { "from_claim": "11111111-1111-1111-1111-111111111111", "to_claim": "22222222-2222-2222-2222-222222222222", "edge_type": "supports", } }, } def test_assert_approvable_allows_strict_pending_payload(): approve.assert_approvable(_strict_pending(), "m3ta", "approved from Telegram") def test_assert_approvable_rejects_missing_review_note(): with pytest.raises(SystemExit): approve.assert_approvable(_strict_pending(), "m3ta", "") def test_assert_approvable_rejects_empty_reviewer(): with pytest.raises(SystemExit): approve.assert_approvable(_strict_pending(), " ", "approved") def test_assert_approvable_rejects_already_approved(): proposal = _strict_pending() proposal["status"] = "approved" with pytest.raises(SystemExit): approve.assert_approvable(proposal, "m3ta", "approved") def test_assert_approvable_rejects_non_applyable_type(): proposal = _strict_pending() proposal["proposal_type"] = "rewrite_claim" with pytest.raises(SystemExit): approve.assert_approvable(proposal, "m3ta", "approved") def test_assert_approvable_rejects_freeform_without_apply_payload(): proposal = _strict_pending() proposal["payload"] = {"rationale": "looks approved in chat"} with pytest.raises(SystemExit): approve.assert_approvable(proposal, "m3ta", "approved") def test_build_approve_sql_has_required_guards(): proposal = _strict_pending() sql = approve.build_approve_sql(proposal, "m3ta", "O'Brien approves") assert "kb_stage.approve_strict_proposal" in sql assert "update kb_stage.kb_proposals" not in sql.lower() assert "E'00957f6c-9883-4015-95a4-6b09367efb0e'::uuid" in sql assert "E'add_edge'" in sql assert "edge_type" in sql assert "supports" in sql assert "E'O''Brien approves'" in sql assert "set local standard_conforming_strings = on" in sql.lower() prereqs = (REPO_ROOT / "scripts" / "kb_apply_prereqs.sql").read_text(encoding="utf-8") for proposal_type in ("add_edge", "attach_evidence", "revise_strategy", "approve_claim"): assert f"'{proposal_type}'" in prereqs def test_approval_prereqs_bind_exact_payload_and_authenticated_principal(): prereqs = (REPO_ROOT / "scripts" / "kb_apply_prereqs.sql").read_text(encoding="utf-8").lower() assert "p_expected_proposal_type" in prereqs assert "p_expected_payload" in prereqs assert "payload = p_expected_payload" in prereqs assert "kb_review_principals" in prereqs assert "session_user::name" in prereqs assert "kb_proposal_approvals" in prereqs assert "owner to kb_gate_owner" in prereqs assert "set search_path = pg_catalog, pg_temp" in prereqs def test_review_cli_uses_separate_role_and_secret_defaults(): args = approve.parse_args( [ "00957f6c-9883-4015-95a4-6b09367efb0e", "--reviewed-by", "m3ta", "--review-note", "approved", ] ) assert args.role == "kb_review" assert args.secrets_file.endswith("kb-review.env") prereqs = (REPO_ROOT / "scripts" / "kb_apply_prereqs.sql").read_text(encoding="utf-8").lower() assert "revoke update on kb_stage.kb_proposals from kb_apply" in prereqs assert "grant execute on function kb_stage.approve_strict_proposal" in prereqs assert "to kb_review" in prereqs assert "grant execute on function kb_stage.assert_approved_proposal" in prereqs assert "grant execute on function kb_stage.finish_approved_proposal" in prereqs assert "to kb_apply" in prereqs def test_parse_reviewed_rows_requires_exactly_one_row(): rows = approve.parse_reviewed_rows( '[{"id":"00957f6c-9883-4015-95a4-6b09367efb0e","status":"approved"}]', "00957f6c-9883-4015-95a4-6b09367efb0e", ) assert rows[0]["status"] == "approved" with pytest.raises(SystemExit): approve.parse_reviewed_rows("[]", "00957f6c-9883-4015-95a4-6b09367efb0e") if __name__ == "__main__": import traceback failures = 0 for name, fn in sorted(globals().items()): if name.startswith("test_") and callable(fn): try: fn() print(f"PASS {name}") except Exception: failures += 1 print(f"FAIL {name}") traceback.print_exc() sys.exit(1 if failures else 0)