From 5a272ed27c1a515495f2709487a4d7c23a3b7919 Mon Sep 17 00:00:00 2001 From: Goose Date: Tue, 31 Mar 2026 17:50:42 +0000 Subject: [PATCH] restore github-app-token skill docs, remove script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep SKILL.md with inline token generation commands and env var docs. Delete the bundled generate_token.sh script — no backward compatibility shims. Co-Authored-By: Paperclip --- CLAUDE.md | 1 + github-app-token/SKILL.md | 80 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 github-app-token/SKILL.md diff --git a/CLAUDE.md b/CLAUDE.md index 89e7f49..8eab502 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,6 +14,7 @@ Each skill follows this convention: ## Current Skills +- **`github-app-token`** — Documents how to generate short-lived GitHub App installation access tokens. Requires `GITHUB_APP_ID`, `GITHUB_APP_INSTALLATION_ID`, and `GITHUB_APP_PEM_FILE` env vars. Inline commands only — no bundled scripts. - **`playwright-ephemeral`** — Provisions ephemeral Playwright MCP browser sessions as Kubernetes Jobs for E2E testing. Creates a Job + Service pair in a dedicated namespace, waits for readiness, and returns the MCP endpoint URL. Requires `kubectl` and appropriate RBAC. ## Key Patterns diff --git a/github-app-token/SKILL.md b/github-app-token/SKILL.md new file mode 100644 index 0000000..eb3ec2a --- /dev/null +++ b/github-app-token/SKILL.md @@ -0,0 +1,80 @@ +--- +name: github-app-token +description: Generate a GitHub installation access token from a GitHub App PEM key, App ID, and Installation ID, then authenticate the gh CLI with it. +--- + +# GitHub App Token Skill + +Generate a short-lived GitHub installation access token from a GitHub App's credentials and use it to authenticate the `gh` CLI. + +## Prerequisites + +The following environment variables MUST be set before invoking this skill: + +| Variable | Description | +|---|---| +| `GITHUB_APP_ID` | The numeric App ID from the GitHub App settings page | +| `GITHUB_APP_INSTALLATION_ID` | The numeric Installation ID for the target org/user | +| `GITHUB_APP_PEM_FILE` | Absolute path to the GitHub App's PEM private key file | + +If any variable is missing, stop and tell the user which ones are required. + +Requires `openssl`, `curl`, and `jq`. + +## Generate a Token + +Build a JWT signed with the App's private key, then exchange it for an installation access token: + +```bash +# Base64url helper +b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; } + +# Build JWT (valid 10 minutes) +NOW=$(date +%s) +HEADER=$(printf '{"alg":"RS256","typ":"JWT"}' | jq -r -c .) +PAYLOAD=$(printf '{"iat":%s,"exp":%s,"iss":"%s"}' "$NOW" "$((NOW + 600))" "$GITHUB_APP_ID" | jq -r -c .) +SIGNED=$(printf '%s' "$HEADER" | b64enc).$(printf '%s' "$PAYLOAD" | b64enc) +SIG=$(printf '%s' "$SIGNED" | openssl dgst -binary -sha256 -sign "$GITHUB_APP_PEM_FILE" | b64enc) +JWT="${SIGNED}.${SIG}" + +# Exchange JWT for installation token +GH_TOKEN=$(curl -s -X POST \ + -H "Authorization: Bearer ${JWT}" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/app/installations/${GITHUB_APP_INSTALLATION_ID}/access_tokens" \ + | jq -r '.token') + +export GH_TOKEN +``` + +## Authenticate the gh CLI + +With `GH_TOKEN` exported, the `gh` CLI uses it automatically for API operations: + +```bash +gh api user +``` + +To persist into `gh auth` config: + +```bash +echo "${GH_TOKEN}" | gh auth login --with-token +``` + +## Cleanup + +The installation access token expires after 1 hour. To revoke it early: + +```bash +curl -s -X DELETE \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/installation/token" +``` + +## Security Notes + +- Never log or echo the PEM key or installation token to stdout in production. +- The installation token is valid for 1 hour from generation. +- Store the PEM file with restrictive permissions (`chmod 600`) and never check it into git.