#!/usr/bin/env python3 """ Minimal GitHub / Gitea API helper for Gatekeep (no gh CLI required). Uses GITHUB_API_URL + GITHUB_TOKEN (Gitea Actions sets these to the forge). """ from __future__ import annotations import json import os import sys import urllib.error import urllib.parse import urllib.request def api_base() -> str: base = (os.environ.get("GITHUB_API_URL") or "https://api.github.com").rstrip("/") return base def is_gitea() -> bool: b = api_base().lower() return "api.github.com" not in b def token() -> str: return ( os.environ.get("GITHUB_TOKEN") or os.environ.get("GITEA_TOKEN") or os.environ.get("GH_TOKEN") or "" ) def request(method: str, path: str, body: dict | None = None, accept: str | None = None) -> tuple[int, str]: path = path if path.startswith("/") else f"/{path}" url = f"{api_base()}{path}" data = None if body is None else json.dumps(body).encode("utf-8") headers = { "Authorization": f"token {token()}" if is_gitea() else f"Bearer {token()}", "Accept": accept or ("application/json" if is_gitea() else "application/vnd.github+json"), "User-Agent": "gatekeep-action", } if body is not None: headers["Content-Type"] = "application/json" # GitHub also accepts token prefix if not is_gitea() and token(): headers["Authorization"] = f"Bearer {token()}" req = urllib.request.Request(url, data=data, headers=headers, method=method.upper()) try: with urllib.request.urlopen(req, timeout=120) as resp: return resp.status, resp.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as e: return e.code, e.read().decode("utf-8", errors="replace") def request_json(method: str, path: str, body: dict | None = None): code, text = request(method, path, body) if code >= 400: raise RuntimeError(f"{method} {path} → HTTP {code}: {text[:500]}") if not text.strip(): return None return json.loads(text) def main(argv: list[str]) -> int: """CLI: forge_api.py METHOD PATH [json-body] → prints response body""" if len(argv) < 3: print("usage: forge_api.py METHOD /path [json-body]", file=sys.stderr) return 2 method, path = argv[1], argv[2] body = json.loads(argv[3]) if len(argv) > 3 else None code, text = request(method, path, body) sys.stdout.write(text) return 0 if code < 400 else 1 if __name__ == "__main__": raise SystemExit(main(sys.argv))