from __future__ import annotations

import importlib.util
import sys
import unittest
from pathlib import Path

REPO_DIR = Path(__file__).resolve().parents[1]
SPEC = importlib.util.spec_from_file_location(
    "credential_grants_validate", REPO_DIR / "scripts/credential-grants-validate.py"
)
grants = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
sys.modules[SPEC.name] = grants
SPEC.loader.exec_module(grants)


class CredentialGrantBindTests(unittest.TestCase):
    def test_catalog_validates(self) -> None:
        errors: list[str] = []
        catalog = grants.yaml.safe_load(
            (REPO_DIR / "credential-grants/catalog.yaml").read_text()
        )
        for index, grant in enumerate(catalog["grants"]):
            grants.validate_grant(grant, index, catalog, errors)
        self.assertEqual(errors, [])

    def test_postgres_grants_bind_rapp(self) -> None:
        catalog = grants.yaml.safe_load(
            (REPO_DIR / "credential-grants/catalog.yaml").read_text()
        )
        bound = {
            grant["id"]: grant.get("rapp_id")
            for grant in catalog["grants"]
            if str(grant["id"]).startswith("rapp-")
        }
        self.assertEqual(
            bound,
            {
                "rapp-postgres/audit-core-runtime": "rapp-postgres",
                "rapp-postgres/audit-core-migration": "rapp-postgres",
            },
        )

    def test_rapp_prefix_requires_matching_rapp_id(self) -> None:
        errors: list[str] = []
        grant = {
            "id": "rapp-postgres/audit-core-runtime",
            "title": "x",
            "description": "x",
            "status": "active",
            "grant_class": "self-service",
            "credential_type": "openbao-database-credential",
            "issuer": "openbao",
            "audience": "audit-core",
            "openbao": {
                "token_role": "audit-core-runtime-broker",
                "issuer_policy": "credential-broker-audit-core-runtime-issuer",
                "policies": ["credential-broker-audit-core-runtime"],
                "disallowed_policies": ["root", "platform-admin"],
                "mount_paths": ["database/creds/audit-core-runtime"],
            },
            "ttl": {"default": "15m", "max": "1h", "renewable": False},
            "actors": {"allowed_types": ["human-operator"]},
            "authorization": {
                "flex_auth_required": False,
                "purpose_required": True,
            },
            "delivery": {
                "allowed": ["exec-env"],
                "preferred": "exec-env",
                "denied": [
                    "chat",
                    "state-hub-body",
                    "git",
                    "command-line-token-argument",
                    "llm-prompt",
                ],
            },
            "audit": {
                "openbao_audit_required": True,
                "record_secret_values": False,
            },
            "revocation": {"required": True, "by_accessor": True},
        }
        grants.validate_grant(grant, 0, {}, errors)
        self.assertTrue(any("rapp_id is required" in error for error in errors))
        errors.clear()
        grant["rapp_id"] = "rapp-openbao"
        grants.validate_grant(grant, 0, {}, errors)
        self.assertTrue(any("must equal the grant id prefix" in error for error in errors))
