Gatekeep evals / eval-floor (push) Successful in 8s
Add .github/workflows/gatekeep-pr.yml with uses: ./ and OPENROUTER_API_KEY from secrets. Forge-agnostic API helper for Gitea.
80 lines
2.5 KiB
Python
80 lines
2.5 KiB
Python
#!/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))
|