diff --git a/gh-cli/github-app-manifest-form.html b/gh-cli/github-app-manifest-form.html new file mode 100644 index 0000000..fc45977 --- /dev/null +++ b/gh-cli/github-app-manifest-form.html @@ -0,0 +1,155 @@ + + + + GitHub App Manifest Test + + + +
+

GitHub App Manifest Test

+ +
+ What happens next: +
    +
  1. Start a local server (see instructions below)
  2. +
  3. Click "Create GitHub App" below
  4. +
  5. GitHub will redirect you to review and create the app
  6. +
  7. After creation, GitHub redirects back with a temporary code
  8. +
  9. The code will be automatically displayed and you can copy it
  10. +
+
+ +
+ 🚀 How to start local server (click to expand) + +
+ +
+ ⚠️ Important Notes (click to expand) + +
+ + + + +
+

App Manifest Configuration:

+ +

+ +
+ +
+ 📋 How to use the manifest code (click to expand) + +
+
+ + + + diff --git a/scripts/README.md b/scripts/README.md index 9821c6c..e818d88 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -36,15 +36,7 @@ Configuration values to change in the script: Migrate work items from Azure DevOps to GitHub issues - this just links out to a [separate repo](https://github.com/joshjohanning/ado_workitems_to_github_issues) -## delete-branch-protection-rules.ps1 - -Delete branch protection rules programmatically based on a pattern. - -## gei-clean-up-azure-storage-account.sh - -Clean up Azure Storage Account Containers from GEI migrations. - -## get-app-jwt.py +## create-app-jwt.py This script will generate a JWT for a GitHub App. It will use the private key and app ID from the GitHub App's settings page. @@ -55,6 +47,29 @@ This script will generate a JWT for a GitHub App. It will use the private key an Script sourced from [GitHub docs](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-python-to-generate-a-jwt). +## create-app-jwt.sh + +Generate a JWT (JSON Web Token) for a GitHub App using bash. This is a shell script alternative to `create-app-jwt.py`. + +Usage: + +```bash +./create-app-jwt.sh +``` + +The script generates a JWT that is valid for 10 minutes, which can be used to authenticate as a GitHub App and obtain installation tokens. + +> [!NOTE] +> Requires `openssl` to be installed. The JWT can be used with the GitHub API to generate installation access tokens. + +## delete-branch-protection-rules.ps1 + +Delete branch protection rules programmatically based on a pattern. + +## gei-clean-up-azure-storage-account.sh + +Clean up Azure Storage Account Containers from GEI migrations. + ## get-app-tokens-for-each-installation.sh This script will generate generate a JWT for a GitHub app and use that JWT to generate installation tokens for each org installation. The installation tokens, returned as `ghs_abc`, can then be used for normal API calls. It will use the private key and app ID from the GitHub App's settings page and the `get-app-jwt.py` script to generate the JWT, and then use the JWT to generate the installation tokens for each org installation. @@ -94,6 +109,26 @@ My use case is to use this list to determine who needs to be added to a organiza 1. Run: `./new-users-to-add-to-project.sh ` 2. Don't delete the `` as it functions as your user database +## github-app-manifest-flow + +Scripts to create GitHub Apps using the [GitHub App Manifest flow](https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest). The manifest flow allows you to create a GitHub App by posting a JSON manifest to GitHub, which then generates the app credentials. + +**Workflow:** + +1. **Generate HTML form**: Run `generate-github-app-manifest-form.sh [organization]` to create an HTML file +2. **Start local server**: Serve the HTML file (e.g., `python3 -m http.server 8000`) +3. **Create app via browser**: Open the form, submit it to GitHub, and get redirected back with a manifest code +4. **Convert manifest code**: Use `create-github-app-from-manifest.sh` to convert the code into app credentials + +**Scripts:** + +- **generate-github-app-manifest-form.sh**: Generates an HTML form for the manifest flow +- **create-github-app-from-manifest.sh**: Converts manifest code into app credentials with detailed output and error handling +- **github-app-manifest-form-example.html**: Example HTML form (generated output) + +> [!NOTE] +> Requires `curl`, `jq`, and a classic GitHub personal access token (`ghp_*`). Fine-grained tokens are not supported for the manifest conversion endpoint. + ## migrate-discussions See: [migrate-discussions](./migrate-discussions/README.md) diff --git a/scripts/get-app-jwt.py b/scripts/create-app-jwt.py similarity index 100% rename from scripts/get-app-jwt.py rename to scripts/create-app-jwt.py diff --git a/scripts/create-app-jwt.sh b/scripts/create-app-jwt.sh new file mode 100755 index 0000000..bd137f5 --- /dev/null +++ b/scripts/create-app-jwt.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# ----------------------------------------------------------------------------- +# Script to create a JWT (JSON Web Token) signed with a private RSA key. +# +# Usage: +# ./create-app-jwt.sh +# +# Arguments: +# The GitHub App ID (integer) or Client ID (Iv1.xxx) +# to use as the JWT issuer (iss). Both work. +# Path to the PEM-encoded RSA private key file. +# +# Example: +# ./create-app-jwt.sh 123456 /path/to/private-key.pem +# ./create-app-jwt.sh Iv1.abc123def456 /path/to/private-key.pem +# +# The script outputs the generated JWT to stdout. +# ----------------------------------------------------------------------------- +set -o pipefail + +# Input validation for required parameters +if [ -z "$1" ] || [ -z "$2" ]; then + echo "Error: Missing required parameters." >&2 + echo "Usage: $0 " >&2 + exit 1 +fi + +app_id_or_client_id=$1 # App ID (integer) or Client ID (Iv1.xxx) - both work + +# Check if the private key file exists and is readable +if [ ! -f "$2" ] || [ ! -r "$2" ]; then + echo "Error: Private key file '$2' does not exist or is not readable." >&2 + exit 1 +fi +pem=$( cat "$2" ) # file path of the private key as second argument + +now=$(date +%s) +iat=$((${now} - 60)) # Issues 60 seconds in the past +exp=$((${now} + 600)) # Expires 10 minutes in the future + +b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; } + +header_json='{ + "typ":"JWT", + "alg":"RS256" +}' +# Header encode +header=$( echo -n "${header_json}" | b64enc ) + +payload_json="{ + \"iat\":${iat}, + \"exp\":${exp}, + \"iss\":\"${app_id_or_client_id}\" +}" +# Payload encode +payload=$( echo -n "${payload_json}" | b64enc ) + +# Signature +header_payload="${header}"."${payload}" +signature=$( + openssl dgst -sha256 -sign <(echo -n "${pem}") \ + <(echo -n "${header_payload}") | b64enc +) + +# Create JWT +JWT="${header_payload}"."${signature}" +printf '%s\n' "$JWT" diff --git a/scripts/github-app-manifest-flow/README.md b/scripts/github-app-manifest-flow/README.md new file mode 100644 index 0000000..8ae661e --- /dev/null +++ b/scripts/github-app-manifest-flow/README.md @@ -0,0 +1,236 @@ +# GitHub App Manifest Scripts + +Scripts for creating GitHub Apps using the [GitHub App Manifest flow](https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest). The manifest flow is a streamlined way to create GitHub Apps by posting a JSON configuration to GitHub, which automatically generates the app and returns credentials including a private key. + +## Overview + +The GitHub App Manifest flow allows you to: + +- Create GitHub Apps programmatically without manual configuration +- Automatically generate and receive private keys +- Set up apps for users or organizations through a web-based flow +- Simplify GitHub App creation for testing or development environments + +## Workflow + +### 1. Generate HTML Form + +Create an HTML form that will initiate the manifest flow: + +```bash +./generate-github-app-manifest-form.sh [organization] +``` + +**For an organization:** + +```bash +./generate-github-app-manifest-form.sh my-org +``` + +**For a personal account:** + +```bash +./generate-github-app-manifest-form.sh +``` + +This creates a `github-app-manifest-form.html` file with: + +- Pre-configured manifest JSON +- Instructions for local server setup +- Automatic code capture when GitHub redirects back +- Dropdown sections with detailed usage instructions + +### 2. Serve the HTML File + +The HTML file must be served over HTTP (not opened as `file://`). Start a local server: + +```bash +# Python 3 +python3 -m http.server 8000 + +# Python 2 +python -m SimpleHTTPServer 8000 + +# Node.js +npx http-server -p 8000 + +# PHP +php -S localhost:8000 +``` + +Then open: `http://localhost:8000/github-app-manifest-form.html` + +### 3. Create the App + +1. Click "Create GitHub App from Manifest" in the form +2. GitHub redirects you to review the app configuration +3. Click "Create GitHub App" on GitHub's page +4. GitHub redirects back to your local server with a manifest code in the URL +5. The code is automatically displayed in the success message + +### 4. Convert Manifest Code + +Use the manifest code to retrieve your app credentials: + +```bash +export GITHUB_TOKEN=ghp_abc # Classic PAT required +./create-github-app-from-manifest.sh +``` + +The script will: + +- Convert the manifest code into app credentials +- Display the app ID, client ID, client secret, and webhook secret +- Automatically save the private key to a file: `..private-key.pem` + +## Scripts + +### generate-github-app-manifest-form.sh + +Generates an interactive HTML form for the GitHub App Manifest flow. + +**Usage:** + +```bash +./generate-github-app-manifest-form.sh [organization] +``` + +**Features:** + +- Creates customized form for organization or personal account +- Includes collapsible sections with detailed instructions +- Automatically captures and displays the manifest code on redirect +- Provides copy-paste commands for next steps + +**Output:** `github-app-manifest-form.html` + +### create-github-app-from-manifest.sh + +Converts a manifest code into GitHub App credentials with detailed output and error handling. + +**Usage:** + +```bash +export GITHUB_TOKEN=ghp_abc +./create-github-app-from-manifest.sh +``` + +**Features:** + +- Comprehensive error checking and validation +- Detailed explanations of what a manifest code is +- Formatted JSON output with all app details +- Automatic private key file creation +- Helpful instructions for next steps + +**Requirements:** + +- `curl` +- `jq` +- Classic GitHub personal access token (fine-grained tokens not supported) + +**Output:** + +- JSON with app ID, client ID, secrets, permissions, and events +- Private key file: `..private-key.pem` + +### github-app-manifest-form-example.html + +Example of the generated HTML form. This file demonstrates what the `generate-github-app-manifest-form.sh` script creates. + +**Note:** This is a sample output file and should not be edited directly. Regenerate it using the shell script. + +## Requirements + +- **curl**: For API requests +- **jq**: For JSON parsing +- **Classic GitHub PAT**: Fine-grained tokens are not supported for the manifest conversion endpoint + - Token must start with `ghp_` + - No specific scopes required for the conversion endpoint +- **Local HTTP server**: To serve the HTML form (Python, Node.js, PHP, etc.) + +## Complete Example + +```bash +# Step 1: Generate the form +./generate-github-app-manifest-form.sh my-org + +# Step 2: Start a local server +python3 -m http.server 8000 + +# Step 3: Open in browser +# Visit: http://localhost:8000/github-app-manifest-form.html +# Click "Create GitHub App from Manifest" +# Complete the flow on GitHub +# Get redirected back with code (e.g., code=a180b1a3d263c81bc6441d7b990bae27d4c10679) + +# Step 4: Convert the code to credentials +export GITHUB_TOKEN=ghp_your_classic_token_here +./create-github-app-from-manifest.sh a180b1a3d263c81bc6441d7b990bae27d4c10679 + +# Output: JSON with credentials + my-app.2024-01-15.private-key.pem +``` + +## Important Notes + +- **Manifest codes expire in 1 hour** and can only be used once +- **Fine-grained tokens are NOT supported** - you must use a classic personal access token +- The private key can only be retrieved during this conversion - save it securely +- Client secret and webhook secret are also only shown once +- The HTML form must be served over HTTP, not opened as a local file + +## Customizing the Manifest + +To customize the app configuration, edit the `manifest` object in the generated HTML file before submitting: + +```javascript +const manifest = { + name: 'My Custom App', + url: 'https://www.example.com', + hook_attributes: { + url: 'https://example.com/github/events' + }, + redirect_url: redirectUrl, + callback_urls: [redirectUrl], + public: false, + default_permissions: { + metadata: 'read', + contents: 'write', + issues: 'write', + pull_requests: 'write' + }, + default_events: ['issues', 'pull_request', 'push'] +}; +``` + +See the [GitHub App Manifest documentation](https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest#github-app-manifest-parameters) for all available parameters. + +## Troubleshooting + +### "Fine-grained tokens are not supported" + +The manifest conversion endpoint only accepts classic personal access tokens (starting with `ghp_`). Create one at: Settings → Developer settings → Personal access tokens → Tokens (classic) + +### "No parser could be inferred for file" + +Make sure `jq` is installed: + +```bash +brew install jq # macOS +apt-get install jq # Ubuntu/Debian +yum install jq # CentOS/RHEL +``` + +### "Error: manifest code is required" + +The manifest code comes from GitHub after completing the web flow. You cannot generate it manually. + +### Form doesn't work when opened as file:// + +The HTML form must be served over HTTP. Use one of the local server commands provided in the workflow section. + +## References + +- [GitHub App Manifest Flow Documentation](https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest) +- [Create a GitHub App from a manifest API](https://docs.github.com/en/rest/apps/apps#create-a-github-app-from-a-manifest) +- [GitHub App Manifest Parameters](https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest#github-app-manifest-parameters) diff --git a/scripts/github-app-manifest-flow/create-github-app-from-manifest.sh b/scripts/github-app-manifest-flow/create-github-app-from-manifest.sh new file mode 100755 index 0000000..b486284 --- /dev/null +++ b/scripts/github-app-manifest-flow/create-github-app-from-manifest.sh @@ -0,0 +1,146 @@ +#!/bin/bash + +# Create a GitHub App from a manifest +# This script converts a temporary manifest code into GitHub App credentials +# Uses curl instead of GitHub CLI for better portability +# +# WHAT IS A MANIFEST CODE? +# The manifest code is a temporary code generated by GitHub during the App Manifest flow. +# It's NOT something you create yourself. Here's how to get one: +# +# 1. Create an HTML form that posts to GitHub's manifest endpoint with your app configuration +# 2. User clicks "Create GitHub App" +# 3. GitHub redirects back to your site with a temporary code parameter +# 4. Use that code with this script to get the actual app credentials +# +# Usage: ./create-github-app-from-manifest.sh +# +# Example: ./create-github-app-from-manifest.sh a180b1a3d263c81bc6441d7b990bae27d4c10679 +# +# Required: curl, jq, and GITHUB_TOKEN environment variable with a valid CLASSIC GitHub token +# Note: The manifest code expires in 1 hour and can only be used once +# +# For full manifest flow documentation: +# https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest +# +# API Reference: https://docs.github.com/en/rest/apps/apps#create-a-github-app-from-a-manifest + +set -e + +# Check for required dependencies +if ! command -v curl &> /dev/null; then + echo "Error: curl is required but not installed" + exit 1 +fi + +if ! command -v jq &> /dev/null; then + echo "Error: jq is required but not installed" + echo "Install with: brew install jq # macOS" + echo " : apt-get install jq # Ubuntu/Debian" + echo " : yum install jq # CentOS/RHEL" + exit 1 +fi + +# Check if required arguments are provided +if [ $# -eq 0 ]; then + echo "Error: Manifest code is required" + echo "Usage: $0 " + echo "" + echo "Example: $0 a180b1a3d263c81bc6441d7b990bae27d4c10679" + echo "" + echo "WHAT IS A MANIFEST CODE?" + echo "The manifest code is generated by GitHub during the App Manifest flow:" + echo "1. Create an HTML form that posts to GitHub with your app configuration" + echo "2. User submits the form and GitHub redirects back with a 'code' parameter" + echo "3. Use that code with this script to get the actual app credentials" + echo "" + echo "For the complete manifest flow, see:" + echo "https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest" + exit 1 +fi + +# Check for GitHub token +if [ -z "$GITHUB_TOKEN" ]; then + echo "Error: GITHUB_TOKEN environment variable is required" + echo "Set it with: export GITHUB_TOKEN=your_token_here" + exit 1 +fi + +# Check if it's a classic token (starts with ghp_) +if [[ ! "$GITHUB_TOKEN" =~ ^ghp_ ]]; then + echo "Error: GITHUB_TOKEN must be a classic personal access token (starts with 'ghp_')" + echo "Fine-grained tokens are not supported for this endpoint" + exit 1 +fi + +MANIFEST_CODE="$1" + +echo "Converting manifest code to GitHub App credentials..." +echo "Manifest code: $MANIFEST_CODE" +echo "" + +# Make the API call to convert the manifest code using curl +RESPONSE=$(curl -s -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/app-manifests/$MANIFEST_CODE/conversions") + +# gh api example +# # Make the API call to convert the manifest code +# RESPONSE=$(gh api \ +# --method POST \ +# -H "Accept: application/vnd.github+json" \ +# -H "X-GitHub-Api-Version: 2022-11-28" \ +# "/app-manifests/$MANIFEST_CODE/conversions") + +# Check if the request was successful +if ! echo "$RESPONSE" | jq -e . > /dev/null 2>&1; then + echo "❌ Error: Failed to parse JSON response" + echo "Response: $RESPONSE" + exit 1 +fi + +# Check for API errors +if echo "$RESPONSE" | jq -e '.message' > /dev/null 2>&1; then + echo "❌ API Error:" + echo "$RESPONSE" | jq -r '.message' + if echo "$RESPONSE" | jq -e '.documentation_url' > /dev/null 2>&1; then + echo "Documentation: $(echo "$RESPONSE" | jq -r '.documentation_url')" + fi + exit 1 +fi + +# Extract values for file naming +APP_NAME=$(echo "$RESPONSE" | jq -r '.name // .slug' | tr ' ' '_' | tr '[:upper:]' '[:lower:]') +CURRENT_DATE=$(date +%Y-%m-%d) +PEM_FILENAME="${APP_NAME}.${CURRENT_DATE}.private-key.pem" + +# Save the PEM to a file +echo "$RESPONSE" | jq -r '.pem' > "$PEM_FILENAME" + +# Display the formatted response +echo "$RESPONSE" | jq '{ + id: .id, + slug: .slug, + name: .name, + description: .description, + client_id: .client_id, + client_secret: .client_secret, + webhook_secret: .webhook_secret, + pem: .pem, + owner: .owner.login, + html_url: .html_url, + permissions: .permissions, + events: .events +}' + +echo "" +echo "✅ GitHub App created successfully!" +echo "" +echo "Important: Save the client_secret, webhook_secret, and pem values securely." +echo "The pem field contains the full RSA private key for the app." +echo "These credentials cannot be retrieved again through the API." +echo "" +echo "🔑 Private key automatically saved to: $PEM_FILENAME" +echo "💡 You can use this file for GitHub App authentication and JWT generation." diff --git a/scripts/github-app-manifest-flow/generate-github-app-manifest-form.sh b/scripts/github-app-manifest-flow/generate-github-app-manifest-form.sh new file mode 100755 index 0000000..82337c5 --- /dev/null +++ b/scripts/github-app-manifest-flow/generate-github-app-manifest-form.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +# Generate GitHub App Manifest HTML Form +# This script creates an HTML file that demonstrates the GitHub App Manifest flow +# +# Usage: ./generate-github-app-manifest-form.sh [organization] +# +# Example: ./generate-github-app-manifest-form.sh my-org +# ./generate-github-app-manifest-form.sh # for personal account +# +# This creates an HTML file that you can open in a browser to test the manifest flow. +# After submitting the form, GitHub will redirect back with a code that you can use +# with the create-github-app-from-manifest.sh script. +# +# Reference: https://docs.github.com/en/apps/sharing-github-apps/registering-a-github-app-from-a-manifest + +set -e + +ORGANIZATION="$1" +OUTPUT_FILE="github-app-manifest-form.html" + +# Determine the action URL based on whether an organization is specified +if [ -n "$ORGANIZATION" ]; then + ACTION_URL="https://github.com/organizations/$ORGANIZATION/settings/apps/new?state=abc123" + TARGET_TEXT="organization '$ORGANIZATION'" +else + ACTION_URL="https://github.com/settings/apps/new?state=abc123" + TARGET_TEXT="your personal account" +fi + +echo "Generating GitHub App Manifest form for $TARGET_TEXT..." + +cat >"$OUTPUT_FILE" <<'EOF' + + + + + GitHub App Manifest Test + + + +
+

GitHub App Manifest Test

+ +
+ What happens next: +
    +
  1. Start a local server (see instructions below)
  2. +
  3. Click "Create GitHub App" below
  4. +
  5. GitHub will redirect you to review and create the app
  6. +
  7. After creation, GitHub redirects back with a temporary code
  8. +
  9. The code will be automatically displayed and you can copy it
  10. +
+
+ +
+ 🚀 How to start local server (click to expand) + +
+ +
+ ⚠️ Important Notes (click to expand) + +
+ + + + +
+

App Manifest Configuration:

+ +

+ +
+ +
+ 📋 How to use the manifest code (click to expand) + +
+
+ + + + +EOF + +# Replace placeholders with actual values +# Cross-platform approach (works everywhere) +sed "s|ACTION_URL_PLACEHOLDER|$ACTION_URL|g" "$OUTPUT_FILE" > "$OUTPUT_FILE.tmp" +mv "$OUTPUT_FILE.tmp" "$OUTPUT_FILE" +sed "s|TARGET_PLACEHOLDER|$TARGET_TEXT|g" "$OUTPUT_FILE" > "$OUTPUT_FILE.tmp" +mv "$OUTPUT_FILE.tmp" "$OUTPUT_FILE" + +echo "✅ Generated HTML form: $OUTPUT_FILE" +echo "" +echo "Next steps:" +echo "1. Start a local HTTP server in this directory:" +echo " python3 -m http.server 8000" +echo "2. Open http://localhost:8000/$OUTPUT_FILE in your browser" +echo "3. Click 'Create GitHub App from Manifest'" +echo "4. Follow GitHub's prompts to create the app" +echo "5. GitHub will redirect back with a code parameter automatically displayed" +echo "6. Use that code with: ./create-github-app-from-manifest.sh " +echo "" +echo "The form now includes local server setup instructions and automatic code handling!" diff --git a/scripts/github-app-manifest-flow/github-app-manifest-form-example.html b/scripts/github-app-manifest-flow/github-app-manifest-form-example.html new file mode 100644 index 0000000..2151e9f --- /dev/null +++ b/scripts/github-app-manifest-flow/github-app-manifest-form-example.html @@ -0,0 +1,160 @@ + + + + + GitHub App Manifest Test + + + +
+

GitHub App Manifest Test

+ +
+ What happens next: +
    +
  1. Start a local server (see instructions below)
  2. +
  3. Click "Create GitHub App" below
  4. +
  5. GitHub will redirect you to review and create the app
  6. +
  7. After creation, GitHub redirects back with a temporary code
  8. +
  9. The code will be automatically displayed and you can copy it
  10. +
+
+ +
+ 🚀 How to start local server (click to expand) + +
+ +
+ ⚠️ Important Notes (click to expand) + +
+ + + + +
+

App Manifest Configuration:

+ +

+ +
+ +
+ 📋 How to use the manifest code (click to expand) + +
+
+ + + +