"""Tests for D16: the operator key may never be an agent identity. Background: the operator key was, at some point, Cayce's nostr key. The daemon must refuse to operate in that configuration, because "human approval" signed by the agent is not human approval. """ from __future__ import annotations import pytest from cayceops.signing import ( SelfApprovalError, pubkey_from_private_hex, validate_no_self_approval, ) # keys invented for tests only (allowlisted in .gitleaks.toml) CAYCE_SECRET = "11" * 32 # simulates Cayce nostr identity CAYCE_PUBKEY = pubkey_from_private_hex(CAYCE_SECRET) HUMAN_SECRET = "33" * 32 # a proper human operator key HUMAN_PUBKEY = pubkey_from_private_hex(HUMAN_SECRET) def _cfg(monkeypatch, operator_pubkey: str, nostr_private_key: str = CAYCE_SECRET): from cayceops.config import Config monkeypatch.setenv("CAYCE_OPS_DEPLOYMENT_ID", "itest") monkeypatch.setenv("CAYCE_OPS_OPERATOR_PUBKEY", operator_pubkey) monkeypatch.setenv("CAYCE_OPS_NOSTR_PRIVATE_KEY", nostr_private_key) return Config() def test_agent_pubkey_as_operator_is_refused(monkeypatch): """The exact bug: operator pubkey = Cayce pubkey must fail.""" cfg = _cfg(monkeypatch, operator_pubkey=CAYCE_PUBKEY) with pytest.raises(SelfApprovalError): validate_no_self_approval(cfg) def test_human_pubkey_passes(monkeypatch): cfg = _cfg(monkeypatch, operator_pubkey=HUMAN_PUBKEY) validate_no_self_approval(cfg) # does not raise def test_empty_operator_pubkey_passes_validation(monkeypatch): """Empty is the 'not configured' state — rejected elsewhere, not here.""" cfg = _cfg(monkeypatch, operator_pubkey="") validate_no_self_approval(cfg) def test_explicit_denylist_is_honoured(monkeypatch): """A key held outside this process can be listed explicitly.""" outside_pubkey = pubkey_from_private_hex("44" * 32) monkeypatch.setenv( "CAYCE_OPS_FORBIDDEN_OPERATOR_PUBKEYS", f"{outside_pubkey}, {HUMAN_PUBKEY}" ) cfg = _cfg(monkeypatch, operator_pubkey=HUMAN_PUBKEY, nostr_private_key="") with pytest.raises(SelfApprovalError): validate_no_self_approval(cfg) def test_daemon_refuses_to_start_with_agent_key(monkeypatch, sess, db_engine): """End-to-end: executor.run must refuse (exit 2) when the operator pubkey is Cayce's identity.""" from cayceops.components.executor import executor from cayceops.models import DaemonRun cfg = _cfg(monkeypatch, operator_pubkey=CAYCE_PUBKEY) code = executor.run(cfg, sess) assert code == 2 run_row = sess.query(DaemonRun).filter_by(daemon="executor").one() assert run_row.status == "error" assert "agent identity" in run_row.detail["refused"] def test_pubkey_derivation_roundtrip(): assert pubkey_from_private_hex(HUMAN_SECRET) == HUMAN_PUBKEY with pytest.raises(ValueError): pubkey_from_private_hex("") with pytest.raises(ValueError): pubkey_from_private_hex("nothex")