|
| 1 | +# ghapp — GitHub App Auth for git/gh |
| 2 | + |
| 3 | +CLI tool that authenticates as a GitHub App, generates installation tokens, and configures `git` and `gh` to use them transparently. |
| 4 | + |
| 5 | +## Install |
| 6 | + |
| 7 | +```bash |
| 8 | +# Homebrew (macOS/Linux) |
| 9 | +brew tap operator-kit/tap |
| 10 | +brew install ghapp |
| 11 | + |
| 12 | +# One-liner (Linux/macOS) |
| 13 | +curl -sSL https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.sh | bash |
| 14 | + |
| 15 | +# PowerShell (Windows) |
| 16 | +irm https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.ps1 | iex |
| 17 | + |
| 18 | +# Specific version |
| 19 | +curl -sSL https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.sh | GHAPP_VERSION=v0.1.0 bash |
| 20 | + |
| 21 | +# From source (requires Go) |
| 22 | +go install github.com/operator-kit/ghapp-cli/cmd/ghapp@latest |
| 23 | + |
| 24 | +# Build from cloned repo |
| 25 | +go build -o build/ ./cmd/ghapp/ |
| 26 | +go build -o build/ ./cmd/gh-wrapper/ # optional: gh wrapper binary |
| 27 | + |
| 28 | +# Cross-compile |
| 29 | +GOOS=linux GOARCH=arm64 go build -o build/ ./cmd/ghapp/ |
| 30 | +``` |
| 31 | + |
| 32 | +## Prerequisite — Create a GitHub App |
| 33 | + |
| 34 | +You need three values for `ghapp setup`: **App ID**, **Installation ID**, and a **private key** (.pem file). |
| 35 | + |
| 36 | +### 1. Create the app |
| 37 | +- Go to **Settings → Developer settings → GitHub Apps → New GitHub App** ([docs](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app)) |
| 38 | + - For org-owned apps: **Org settings → Developer settings → GitHub Apps** |
| 39 | +- **Name**: anything unique (e.g., `Mr Fox`) - this will be used everywhere your App interacts. |
| 40 | +- **Homepage URL**: can be any URL (e.g., your org's GitHub page) |
| 41 | +- **Webhooks**: uncheck **Active** (not needed) |
| 42 | +The other settings are not needed. |
| 43 | + |
| 44 | +### 2. Set permissions |
| 45 | + |
| 46 | +Select **Repository permissions** based on what you need: |
| 47 | + |
| 48 | +| Use case | Required permissions | |
| 49 | +|----------|---------------------| |
| 50 | +| `git` clone/push/pull | **Contents**: Read & write | |
| 51 | +| `gh` PRs, issues, etc. | **Contents**: Read & write, **Pull requests**: Read & write, **Issues**: Read & write, **Metadata**: Read | |
| 52 | + |
| 53 | +> Add more as needed. `gh pr list` silently returns empty without Issues read permission. |
| 54 | +
|
| 55 | +### 3. Create & note your App ID |
| 56 | +- Click **Create GitHub App** |
| 57 | +- **App ID** is shown at the top of the app's settings page |
| 58 | + |
| 59 | +### 4. Generate a private key |
| 60 | +- On the app settings page, scroll to **Private keys → Generate a private key** |
| 61 | +- A `.pem` file downloads — store it securely (GitHub won't show it again) |
| 62 | + |
| 63 | +### 5. Install the app & note your Installation ID |
| 64 | +- On the app settings page, click **Install App** in the left sidebar |
| 65 | +- Select your account/org and choose which repos to grant access to |
| 66 | +- After installing, the URL will be `github.com/settings/installations/12345678` — the number at the end is your **Installation ID** |
| 67 | + |
| 68 | +## Quick Start |
| 69 | + |
| 70 | +```bash |
| 71 | +# 1. Setup — enter App ID, Installation ID, key path |
| 72 | +# (optionally configures git + gh auth at the end) |
| 73 | +ghapp setup |
| 74 | + |
| 75 | +# 2. Use git/gh normally — auth is transparent |
| 76 | +git clone https://github.com/org/repo.git |
| 77 | +gh pr list |
| 78 | +``` |
| 79 | + |
| 80 | +> If you skipped auth configuration during setup, run `ghapp auth configure` separately. |
| 81 | +
|
| 82 | +## Commands |
| 83 | + |
| 84 | +| Command | Description | |
| 85 | +|---------|-------------| |
| 86 | +| `ghapp setup [--import-key]` | Interactive setup — App ID, Installation ID, PEM key | |
| 87 | +| `ghapp token [--no-cache]` | Print an installation token (cached; `--no-cache` forces fresh) | |
| 88 | +| `ghapp auth configure [--gh-auth MODE]` | Configure git credential helper, gh CLI, and git identity | |
| 89 | +| `ghapp auth status` | Show current auth configuration and diagnostics | |
| 90 | +| `ghapp auth reset [--remove-key]` | Remove all auth config and restore previous git identity | |
| 91 | +| `ghapp update` | Self-update to the latest release | |
| 92 | +| `ghapp version` | Print version info | |
| 93 | + |
| 94 | +### `--gh-auth` modes |
| 95 | + |
| 96 | +During `auth configure`, you're prompted to choose how `gh` CLI gets authenticated. You can also pass it non-interactively: |
| 97 | + |
| 98 | +| Mode | Flag value | Description | |
| 99 | +|------|-----------|-------------| |
| 100 | +| Shell function | `--gh-auth shell-function` | Wraps `gh` with a shell function that injects a fresh token per invocation | |
| 101 | +| PATH binary | `--gh-auth path-shim` | Installs `ghapp-gh` wrapper binary as `gh` earlier in PATH | |
| 102 | +| None | `--gh-auth none` | Only writes `hosts.yml` (token expires in ~1hr) | |
| 103 | + |
| 104 | +## How It Works |
| 105 | + |
| 106 | +### git auth |
| 107 | + |
| 108 | +`ghapp` registers itself as a git credential helper. On every git network operation, git calls `ghapp credential-helper get`, which returns a fresh installation token. Tokens are cached locally so repeated operations within the same session are fast. |
| 109 | + |
| 110 | +`auth configure` also sets `url."https://github.com/".insteadOf "git@github.com:"` so that SSH-style URLs (`git@github.com:org/repo.git`) are transparently rewritten to HTTPS. This means copy-pasted SSH clone URLs and submodules that reference `git@github.com:...` will work automatically. |
| 111 | + |
| 112 | +### git identity |
| 113 | + |
| 114 | +`auth configure` sets `user.name` and `user.email` to the app's bot account (e.g., `myapp[bot]`), so commits are attributed to the app with its icon on GitHub. If you already have a git identity, it will ask before overwriting and backs up your previous identity for `auth reset`. |
| 115 | + |
| 116 | +### gh auth — shell function (recommended) |
| 117 | + |
| 118 | +`auth configure` injects a managed block into your shell's rc file that wraps `gh` with a function. Every `gh` invocation automatically gets a fresh token via `GH_TOKEN`: |
| 119 | + |
| 120 | +```bash |
| 121 | +# What gets added to your .bashrc / .zshrc (managed automatically): |
| 122 | +eval "$(ghapp auth shell-init)" |
| 123 | +``` |
| 124 | + |
| 125 | +Under the hood, this defines a `gh()` function that calls `ghapp token`, sets `GH_TOKEN`, and delegates to the real `gh`. Tokens are cached so the overhead is negligible after the first call. |
| 126 | + |
| 127 | +**Supported shells:** bash, zsh, fish, PowerShell |
| 128 | + |
| 129 | +### gh auth — PATH binary (CI / non-shell) |
| 130 | + |
| 131 | +For environments without shell rc files (CI, containers, cron), the `ghapp-gh` wrapper binary can be placed on PATH as `gh`. It resolves the real `gh`, generates/caches a token, and execs with `GH_TOKEN` set. Falls through to plain `gh` if config is missing. |
| 132 | + |
| 133 | +### Token caching |
| 134 | + |
| 135 | +All token paths (credential helper, `ghapp token`, shell function, wrapper binary) share a local cache file. Tokens are reused until they're within 5 minutes of expiry, then automatically refreshed. This means: |
| 136 | + |
| 137 | +- `ghapp token` returns in <10ms on cache hit |
| 138 | +- Back-to-back `git` operations don't re-generate tokens |
| 139 | +- The shell function adds negligible latency to `gh` commands |
| 140 | + |
| 141 | +## Config |
| 142 | + |
| 143 | +Stored at `~/.config/ghapp/config.yaml`: |
| 144 | + |
| 145 | +```yaml |
| 146 | +app_id: 123456 |
| 147 | +installation_id: 789012 |
| 148 | +private_key_path: /path/to/key.pem |
| 149 | +key_in_keyring: false |
| 150 | +app_slug: myapp # cached after first auth configure |
| 151 | +bot_user_id: 149130343 # cached after first auth configure |
| 152 | +``` |
| 153 | +
|
| 154 | +Environment overrides: `GHAPP_APP_ID`, `GHAPP_INSTALLATION_ID`, `GHAPP_PRIVATE_KEY_PATH`, `GHAPP_NO_UPDATE_CHECK=1` (disable daily update notice) |
| 155 | + |
| 156 | +## Private Key Storage |
| 157 | + |
| 158 | +- **File** (default): path stored in config, key stays on disk |
| 159 | +- **OS Keyring** (`--import-key`): key imported into Windows Credential Manager / macOS Keychain / Linux Secret Service |
0 commit comments