From d9ddb752d7e081399334263517ed08c07cd3b813 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 09:29:19 +0000 Subject: [PATCH 1/2] feat: Add GitHub App token generator script Add Python script to generate GitHub App installation tokens from environment variables (GH_APP_ID and GH_APP_PRIVATE_KEY_PEM_B64). This is needed to run e2e tests with proper authentication. --- get_github_app_token.py | 90 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100755 get_github_app_token.py diff --git a/get_github_app_token.py b/get_github_app_token.py new file mode 100755 index 0000000..738c43b --- /dev/null +++ b/get_github_app_token.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +""" +GitHub App Token Generator + +Generates an installation access token from GitHub App credentials in environment. + +Environment variables required: +- GH_APP_ID: GitHub App ID +- GH_APP_PRIVATE_KEY_PEM_B64: Base64-encoded private key + +Usage: + # Print token to stdout + python get_github_app_token.py + + # Save to file + python get_github_app_token.py > token.txt + + # Use in shell + export GITHUB_TOKEN=$(python get_github_app_token.py) +""" + +import base64 +import os +import sys +import time + +try: + import jwt + import requests +except ImportError: + print("Error: Missing required dependencies", file=sys.stderr) + print("Install with: pip install PyJWT requests cryptography", file=sys.stderr) + sys.exit(1) + + +def get_installation_token(): + """Generate an installation access token for the GitHub App.""" + + # Get credentials from environment + app_id = os.getenv("GH_APP_ID") + private_key_b64 = os.getenv("GH_APP_PRIVATE_KEY_PEM_B64") + + if not all([app_id, private_key_b64]): + print("Error: Missing GH_APP_ID or GH_APP_PRIVATE_KEY_PEM_B64", file=sys.stderr) + sys.exit(1) + + # Decode private key + private_key = base64.b64decode(private_key_b64).decode('utf-8') + + # Generate JWT + now = int(time.time()) + payload = { + "iat": now - 60, + "exp": now + (10 * 60), + "iss": app_id, + } + jwt_token = jwt.encode(payload, private_key, algorithm="RS256") + + # Get installations + headers = { + "Authorization": f"Bearer {jwt_token}", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + } + + response = requests.get("https://api.github.com/app/installations", headers=headers) + response.raise_for_status() + installations = response.json() + + if not installations: + print("Error: No installations found for this GitHub App", file=sys.stderr) + sys.exit(1) + + # Create installation token + installation_id = installations[0]['id'] + url = f"https://api.github.com/app/installations/{installation_id}/access_tokens" + response = requests.post(url, headers=headers) + response.raise_for_status() + + token_info = response.json() + return token_info['token'] + + +if __name__ == "__main__": + try: + token = get_installation_token() + print(token) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) From 1b2759ae4e2efd31762295c680e16573f12aef36 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Dec 2025 09:39:52 +0000 Subject: [PATCH 2/2] refactor: Convert token generator to uv standalone script - Add uv inline script metadata with dependencies - Automatically installs PyJWT, requests, cryptography on uv run - Update usage documentation to reflect uv usage - Remove manual dependency installation requirement --- get_github_app_token.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/get_github_app_token.py b/get_github_app_token.py index 738c43b..adbce6a 100755 --- a/get_github_app_token.py +++ b/get_github_app_token.py @@ -1,4 +1,12 @@ -#!/usr/bin/env python3 +#!/usr/bin/env -S uv run +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "PyJWT", +# "requests", +# "cryptography", +# ] +# /// """ GitHub App Token Generator @@ -9,14 +17,14 @@ - GH_APP_PRIVATE_KEY_PEM_B64: Base64-encoded private key Usage: - # Print token to stdout - python get_github_app_token.py + # Run with uv (automatically installs dependencies) + uv run get_github_app_token.py # Save to file - python get_github_app_token.py > token.txt + uv run get_github_app_token.py > token.txt # Use in shell - export GITHUB_TOKEN=$(python get_github_app_token.py) + export GITHUB_TOKEN=$(uv run get_github_app_token.py) """ import base64 @@ -24,13 +32,8 @@ import sys import time -try: - import jwt - import requests -except ImportError: - print("Error: Missing required dependencies", file=sys.stderr) - print("Install with: pip install PyJWT requests cryptography", file=sys.stderr) - sys.exit(1) +import jwt +import requests def get_installation_token():