galaxis-agent/agent/utils/github_app.py
2026-03-20 14:38:07 +09:00

57 lines
1.9 KiB
Python

"""GitHub App installation token generation."""
from __future__ import annotations
import logging
import os
import time
import httpx
import jwt
logger = logging.getLogger(__name__)
GITHUB_APP_ID = os.environ.get("GITHUB_APP_ID", "")
GITHUB_APP_PRIVATE_KEY = os.environ.get("GITHUB_APP_PRIVATE_KEY", "")
GITHUB_APP_INSTALLATION_ID = os.environ.get("GITHUB_APP_INSTALLATION_ID", "")
def _generate_app_jwt() -> str:
"""Generate a short-lived JWT signed with the GitHub App private key."""
now = int(time.time())
payload = {
"iat": now - 60, # issued 60s ago to account for clock skew
"exp": now + 540, # expires in 9 minutes (max is 10)
"iss": GITHUB_APP_ID,
}
private_key = GITHUB_APP_PRIVATE_KEY.replace("\\n", "\n")
return jwt.encode(payload, private_key, algorithm="RS256")
async def get_github_app_installation_token() -> str | None:
"""Exchange the GitHub App JWT for an installation access token.
Returns:
Installation access token string, or None if unavailable.
"""
if not GITHUB_APP_ID or not GITHUB_APP_PRIVATE_KEY or not GITHUB_APP_INSTALLATION_ID:
logger.debug("GitHub App env vars not fully configured, skipping app token")
return None
try:
app_jwt = _generate_app_jwt()
async with httpx.AsyncClient() as client:
response = await client.post(
f"https://api.github.com/app/installations/{GITHUB_APP_INSTALLATION_ID}/access_tokens",
headers={
"Authorization": f"Bearer {app_jwt}",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
)
response.raise_for_status()
return response.json().get("token")
except Exception:
logger.exception("Failed to get GitHub App installation token")
return None