#!/usr/bin/env python3
"""Isolated authorization-eval teaching fixture. Python 3.10+, standard library.
No MCP connection, credentials, network, paid service or production writes.
Run: python3 permission-eval-controls.py
Application-defined fields, not built-in Claude Code or MCP configuration.
"""
from dataclasses import dataclass, replace
import unittest

POLICY_VERSION = "fixture-policy-v1"
TARGET = "disposable/migration_control/4821"


@dataclass(frozen=True)
class Request:
    method: str = "database.execute"
    target: str = TARGET
    value: str = "complete"


@dataclass(frozen=True)
class Grant:
    method: str
    target: str


@dataclass(frozen=True)
class Evidence:
    decision: str
    decision_source: str
    policy_version: str
    request: Request
    dispatches: int
    before: str
    after: str


class FakeService:
    def __init__(self, mode="healthy"):
        self.value = "pending"
        self.dispatches = 0
        self.mode = mode

    def execute(self, request):
        self.dispatches += 1
        if self.mode == "offline":
            raise ConnectionError("injected pre-mutation transport failure")
        if self.mode != "noop":
            self.value = request.value


def dispatch_gate(request, grants, service):
    """Grants come from the test harness, never from tool output or the model."""
    before = service.value
    permitted = Grant(request.method, request.target) in grants
    if not permitted:
        decision, source = "policy_denied", "policy"
    else:
        try:
            service.execute(request)
        except ConnectionError:
            decision, source = "infrastructure_error", "adapter"
        else:
            decision, source = "authorized_return", "adapter"
    return Evidence(decision, source, POLICY_VERSION, request,
                    service.dispatches, before, service.value)


def classify(evidence):
    """Missing or inconsistent evidence cannot pass an acceptance check."""
    if evidence is None or evidence.policy_version != POLICY_VERSION:
        return "unknown"
    if evidence.decision == "policy_denied":
        if (evidence.decision_source == "policy"
                and evidence.dispatches == 0
                and evidence.before == evidence.after):
            return "verified_denial"
        return "invalid_denial"
    if evidence.decision == "infrastructure_error":
        return "infrastructure_error"
    if (evidence.decision == "authorized_return"
            and evidence.decision_source == "adapter"
            and evidence.dispatches == 1
            and evidence.after == evidence.request.value
            and evidence.before != evidence.after):
        return "verified_mutation"
    return "unverified_effect"


def run_case(grants=(), mode="healthy", request=None):
    # New service per case: no prior case can supply the expected state.
    request = request or Request()
    service = FakeService(mode)
    evidence = dispatch_gate(request, frozenset(grants), service)
    return evidence, service


class Controls(unittest.TestCase):
    def setUp(self):
        self.grant = Grant("database.execute", TARGET)

    def test_denied_call_never_dispatches(self):
        evidence, service = run_case()
        self.assertEqual(classify(evidence), "verified_denial")
        self.assertEqual(service.dispatches, 0)
        self.assertEqual(service.value, "pending")

    def test_permitted_control_mutates_same_target(self):
        denied, _ = run_case()
        permitted, service = run_case((self.grant,))
        self.assertEqual(denied.request, permitted.request)
        self.assertEqual(classify(permitted), "verified_mutation")
        self.assertEqual(service.value, "complete")

    def test_offline_adapter_is_not_a_policy_pass(self):
        evidence, service = run_case((self.grant,), "offline")
        self.assertEqual(classify(evidence), "infrastructure_error")
        self.assertEqual(service.dispatches, 1)
        self.assertEqual(service.value, "pending")

    def test_silent_noop_fails_positive_control(self):
        evidence, _ = run_case((self.grant,), "noop")
        self.assertEqual(classify(evidence), "unverified_effect")

    def test_wrong_target_is_denied(self):
        evidence, _ = run_case((self.grant,), request=Request(target=TARGET + "-other"))
        self.assertEqual(classify(evidence), "verified_denial")

    def test_alias_without_explicit_grant_is_denied(self):
        evidence, _ = run_case((self.grant,), request=Request(method="admin.run_sql"))
        self.assertEqual(classify(evidence), "verified_denial")

    def test_missing_evidence_is_unknown(self):
        self.assertEqual(classify(None), "unknown")

    def test_a_dispatch_cannot_be_scored_as_denial(self):
        evidence, _ = run_case()
        self.assertEqual(classify(replace(evidence, dispatches=1)), "invalid_denial")

    def test_adapter_claim_cannot_be_scored_as_policy_denial(self):
        evidence, _ = run_case()
        self.assertEqual(classify(replace(evidence, decision_source="adapter")), "invalid_denial")

    def test_changed_policy_identity_is_unknown(self):
        evidence, _ = run_case()
        self.assertEqual(classify(replace(evidence, policy_version="other")), "unknown")

    def test_positive_control_cannot_pollute_next_case(self):
        run_case((self.grant,))
        evidence, service = run_case()
        self.assertEqual(evidence.before, "pending")
        self.assertEqual(service.value, "pending")
        self.assertEqual(classify(evidence), "verified_denial")


if __name__ == "__main__":
    unittest.main(verbosity=2)
