#!/usr/bin/env python3
"""Mint, verify, and revoke a coding-agent AppRole token without printing it."""

from __future__ import annotations

import argparse
import json
import os
import subprocess
import sys
import urllib.error
import urllib.request
from typing import Any


DEFAULT_ADDR = "https://bao.coulomb.social"
DATA_PATH = "platform/data/workloads/issue-core/issue-core/issue-core-runtime"
METADATA_PATH = (
    "platform/metadata/workloads/issue-core/issue-core/issue-core-runtime"
)
EXPECTED_POLICIES = {
    "agent-high-risk-boundary",
    "workload-kv-read-issue-core-runtime",
}


def bao_json(args: list[str]) -> dict[str, Any]:
    completed = subprocess.run(
        ["bao", *args],
        check=True,
        capture_output=True,
        text=True,
        timeout=30,
    )
    return json.loads(completed.stdout)


def api_request(
    addr: str,
    method: str,
    path: str,
    *,
    token: str | None = None,
    payload: dict[str, Any] | None = None,
) -> dict[str, Any]:
    headers = {"Content-Type": "application/json"}
    if token:
        headers["X-Vault-Token"] = token
    body = json.dumps(payload).encode() if payload is not None else None
    request = urllib.request.Request(
        f"{addr.rstrip('/')}/v1/{path}", data=body, headers=headers, method=method
    )
    with urllib.request.urlopen(request, timeout=30) as response:
        content = response.read()
    return json.loads(content) if content else {}


def verify(role: str, addr: str) -> dict[str, Any]:
    role_payload = bao_json(
        ["read", "-format=json", f"auth/approle/role/{role}/role-id"]
    )
    role_id = role_payload["data"]["role_id"]
    secret_payload = bao_json(
        ["write", "-format=json", "-f", f"auth/approle/role/{role}/secret-id"]
    )
    secret_id = secret_payload["data"]["secret_id"]

    agent_token: str | None = None
    report: dict[str, Any] = {}
    try:
        login = api_request(
            addr,
            "POST",
            "auth/approle/login",
            payload={"role_id": role_id, "secret_id": secret_id},
        )
        agent_token = login["auth"]["client_token"]
        lookup = api_request(addr, "GET", "auth/token/lookup-self", token=agent_token)
        capabilities = api_request(
            addr,
            "POST",
            "sys/capabilities-self",
            token=agent_token,
            payload={"paths": [DATA_PATH, METADATA_PATH]},
        )
        policies = set(lookup["data"].get("policies", []))
        ttl = int(lookup["data"].get("ttl", 0))
        data_caps = capabilities.get(DATA_PATH, [])
        metadata_caps = capabilities.get(METADATA_PATH, [])
        errors: list[str] = []
        if policies != EXPECTED_POLICIES:
            errors.append(f"unexpected policies: {sorted(policies)}")
        if ttl <= 0 or ttl > 900:
            errors.append(f"TTL outside 1..900 seconds: {ttl}")
        if data_caps != ["deny"]:
            errors.append(f"data capabilities are not deny: {data_caps}")
        if "read" not in metadata_caps or "deny" in metadata_caps:
            errors.append(f"metadata capabilities are not read-only: {metadata_caps}")
        report = {
            "role": role,
            "policies": sorted(policies),
            "ttl": ttl,
            "data_capabilities": data_caps,
            "metadata_capabilities": metadata_caps,
            "deny_wins": data_caps == ["deny"],
            "errors": errors,
            "ok": not errors,
        }
    finally:
        if agent_token:
            try:
                api_request(addr, "POST", "auth/token/revoke-self", token=agent_token)
            except (OSError, urllib.error.HTTPError):
                report.setdefault("errors", []).append("test token self-revocation failed")
                report["ok"] = False
    return report


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--role", default="coding-agent-railiance-platform")
    parser.add_argument("--addr", default=os.environ.get("BAO_ADDR", DEFAULT_ADDR))
    args = parser.parse_args()
    try:
        report = verify(args.role, args.addr)
    except (
        KeyError,
        json.JSONDecodeError,
        OSError,
        subprocess.CalledProcessError,
        subprocess.TimeoutExpired,
        urllib.error.HTTPError,
    ) as exc:
        report = {"role": args.role, "ok": False, "errors": [str(exc)]}
    print(json.dumps(report, indent=2, sort_keys=True))
    return 0 if report["ok"] else 1


if __name__ == "__main__":
    raise SystemExit(main())
