mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 20:53:15 +00:00
* feat: add GitHub PR comment trigger and reply support * refactor: improve readability of GitHub integration * linting * fix: resolve github token from thread metadata and improve PR trigger flow * fix: fall back to OAuth for GitHub webhook when no token in thread metadata * give me commit message github integeration working without a breaking * auth.py refactor * fix: validate cached GitHub token before use to handle expiry * liniting * ci unitest formatting * feat: post PR comments as GitHub App bot instead of user OAuth token * resolved comments * slack resolveed comments * Refactor docstring and comments in get_slack_repo_config Removed unnecessary comments and cleaned up docstring formatting. * cr * cr * cr * cr --------- Co-authored-by: bracesproul <braceasproul@gmail.com>
56 lines
1.9 KiB
Python
56 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
|