#!/usr/bin/env python3 """Validate O11Y Skill installation and optionally authenticate without exposing tokens.""" from __future__ import annotations import argparse import json import os import shutil import time import urllib.error import urllib.request from pathlib import Path from typing import Any from runtime_config import load_runtime_config AUTH_URL = "https://www.ds.us-west-2.aws.observability.tidbcloud.com/client/auth" SKILLS = ( "clinic-api", "o11y-auth", "o11y-data", "o11y-data-export", "o11y-metrics-api", ) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Validate O11Y access for Manual Invoice.") parser.add_argument("--auth", action="store_true") parser.add_argument("--provider", choices=("aws", "gcp", "alicloud"), default="aws") parser.add_argument("--timeout", type=int, default=15) return parser.parse_args() def authenticate(token: str, provider: str, timeout: int) -> dict[str, Any]: payload = json.dumps({"github_token": token, "provider": provider}).encode("utf-8") request = urllib.request.Request( AUTH_URL, data=payload, headers={"Content-Type": "application/json"}, method="POST", ) last_error = "unknown error" for attempt in range(3): try: with urllib.request.urlopen(request, timeout=timeout) as response: body = json.loads(response.read().decode("utf-8")) return { "ok": bool(body.get("token") and body.get("auth0_token")), "provider": body.get("provider") or provider, "has_data_export_token": bool(body.get("token")), "has_auth0_token": bool(body.get("auth0_token")), "has_storage_credentials": bool( body.get("access_key_id") or body.get("access_token") ), } except urllib.error.HTTPError as exc: last_error = f"HTTP {exc.code}" if exc.code == 403: last_error += " (connect to the Office network/Feilian VPN and retry)" except (urllib.error.URLError, TimeoutError) as exc: last_error = type(exc).__name__ if attempt < 2: time.sleep(2**attempt) raise RuntimeError(last_error) def main() -> int: config_path = load_runtime_config() args = parse_args() skills_root = Path(os.environ.get("CODEX_HOME", Path.home() / ".codex")) / "skills" skill_status = { name: (skills_root / name / "SKILL.md").is_file() for name in SKILLS } token = os.environ.get("GITHUB_PAT", "") result: dict[str, Any] = { "status": "ready", "config_path": str(config_path) if config_path else None, "github_token_configured": bool(token), "clinic": { "skill_installed": skill_status["clinic-api"], "auth_configured": bool(os.environ.get("CLINIC_API_KEY")), "auth_required_for_clinic_requests": True, "required_for_o11y_fallback": False, }, "skills": skill_status, "commands": { "curl": bool(shutil.which("curl")), "jq": bool(shutil.which("jq")), "aws": bool(shutil.which("aws")), }, "auth": None, } if ( not all(skill_status.values()) or not token or not result["commands"]["curl"] or not result["commands"]["jq"] ): result["status"] = "missing" if args.auth: if not token: result["auth"] = { "ok": False, "provider": args.provider, "error": "GITHUB_PAT is not configured.", } else: try: result["auth"] = authenticate(token, args.provider, args.timeout) except RuntimeError as exc: result["auth"] = {"ok": False, "provider": args.provider, "error": str(exc)} if not result["auth"]["ok"]: result["status"] = "error" print(json.dumps(result, ensure_ascii=False)) return 0 if result["status"] == "ready" else 3 if __name__ == "__main__": raise SystemExit(main())