- Normalize rich proposals into atomic reviewed canonical graph bundles with exact row verification. - Harden reviewer/apply roles, upgrade ACLs, and prove generic plus Helmer lifecycles in isolated PostgreSQL. - Publish repo-native VPS/GCP/Cory skills and live-readonly GCP inventory without changing the live VPS runtime. `.agents/skills/crabbox/SKILL.md` `.agents/skills/teleo-gcp-parity-ops/SKILL.md` `.agents/skills/teleo-kb-db-change-workflow/SKILL.md` `.agents/skills/teleo-leo-onboarding/SKILL.md` `.agents/skills/teleo-vps-runtime-ops/SKILL.md` `.agents/skills/working-leo-cory-outcomes/SKILL.md` `docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.json` `docs/reports/leo-working-state-20260709/approve-claim-clone-canary-current.md` `docs/reports/leo-working-state-20260709/current-truth-index.md` `docs/reports/leo-working-state-20260709/gcp-cloud-sql-t3-live-readonly-current.json` `docs/reports/leo-working-state-20260709/gcp-cloud-sql-t3-live-readonly-current.md` `docs/reports/leo-working-state-20260709/gcp-cloudsql-studio-parity-gate-current.json` `docs/reports/leo-working-state-20260709/gcp-cloudsql-studio-parity-gate-current.md` `docs/reports/leo-working-state-20260709/gcp-parallel-delegation-current.json` `docs/reports/leo-working-state-20260709/helmer-approve-claim-clone-canary-current.json` `docs/reports/leo-working-state-20260709/helmer-approve-claim-normalization-current.json` `docs/reports/leo-working-state-20260709/skill-pack-manifest.json` `docs/reports/leo-working-state-20260709/skill-pack-readme.md` `docs/reports/leo-working-state-20260709/working-leo-current-state-20260709.md` `docs/reports/leo-working-state-20260709/working-leo-definition-20260709.md` `docs/reports/leo-working-state-20260709/working-leo-execution-plan-current.md` `scripts/apply_proposal.py` `scripts/apply_worker.py` `scripts/approve_proposal.py` `scripts/kb_apply_prereqs.sql` `scripts/kb_proposal_normalize.py` `scripts/probe_gcp_db_parity.py` `scripts/run_approve_claim_clone_canary.py` `scripts/run_approve_claim_isolated_container_canary.sh` `tests/test_apply_proposal.py` `tests/test_apply_worker.py` `tests/test_approve_proposal.py` `tests/test_kb_apply_prereqs.py` `tests/test_kb_proposal_normalize.py` `tests/test_kb_proposal_routes.py` `tests/test_probe_gcp_db_parity.py` `tests/test_repo_skill_pack.py`
156 lines
5.3 KiB
Python
156 lines
5.3 KiB
Python
"""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)
|