mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-12 05:38:57 +02:00
160 lines
8.5 KiB
Markdown
160 lines
8.5 KiB
Markdown
# GitHub App setup and OAuth transition
|
|
|
|
The GitHub App is opt-in for operators. Existing OAuth configuration and resources
|
|
continue working with `GITHUB_APP_ENABLED=false` (the default). This feature uses
|
|
existing repository streaming/proxy paths and does not introduce ZIP uploads or
|
|
permanent repository copies.
|
|
|
|
## Register the GitHub App
|
|
|
|
Create a GitHub App at https://github.com/settings/apps/new. This is separate from
|
|
the existing OAuth App; retain its client credentials and callback.
|
|
|
|
Configure:
|
|
|
|
- Callback URL: `https://YOUR_HOST/github/app/callback`.
|
|
- Setup URL: `https://YOUR_HOST/github/app/setup`; enable **Redirect on update**.
|
|
- Webhook URL: `https://YOUR_HOST/github/app/webhook`; enable webhooks and generate
|
|
a strong random webhook secret.
|
|
- Repository permissions: **Contents: read-only**, **Metadata: read-only**,
|
|
**Pull requests: read-only**, **Pages: read-only**. Do not grant write permissions.
|
|
Pull requests read also permits [reading PR issue comments](https://docs.github.com/en/rest/issues/comments#list-issue-comments); Issues permission is unnecessary.
|
|
- Keep user access token expiration enabled. Private email permission is unnecessary.
|
|
- Leave **Request user authorization (OAuth) during installation** unchecked.
|
|
Anonymous GitHub authorizes the user before opening installation; the setup
|
|
redirect must remain available afterward.
|
|
- Allow installation on any account if this is a public service.
|
|
- Generate a private key and record the App ID, slug, client ID and client secret.
|
|
|
|
GitHub delivers installation, installation repository selection, and App user
|
|
revocation lifecycle events. The webhook verifies raw request bytes before parsing
|
|
JSON. Failed processing returns an error for operational visibility; use GitHub's
|
|
delivery redelivery controls after an outage. Pending installation checks also
|
|
retry on repository access. Access checks verify the user's current repository
|
|
access before each new upstream access.
|
|
|
|
GitHub documents [registration](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app),
|
|
[return redirects](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/about-the-setup-url),
|
|
and [repository preselection for OAuth migration](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/migrating-oauth-apps-to-github-apps).
|
|
|
|
## Environment and deployment
|
|
|
|
Set these on every API process, background worker and streamer:
|
|
|
|
```dotenv
|
|
GITHUB_APP_ENABLED=true
|
|
GITHUB_APP_NEW_CONNECTIONS=true
|
|
GITHUB_OAUTH_ENABLED=true
|
|
GITHUB_APP_ID=123456
|
|
GITHUB_APP_SLUG=your-app-slug
|
|
GITHUB_APP_CLIENT_ID=Iv.your-client-id
|
|
GITHUB_APP_CLIENT_SECRET=your-client-secret
|
|
GITHUB_APP_CALLBACK=https://YOUR_HOST/github/app/callback
|
|
GITHUB_APP_WEBHOOK_SECRET=your-random-webhook-secret
|
|
GITHUB_APP_PRIVATE_KEY_FILE=/run/secrets/github-app.pem
|
|
```
|
|
|
|
Supply the PEM key through a read-only secret mount at that path on **both**
|
|
`anonymous_github` and `streamer`. Alternatively, `GITHUB_APP_PRIVATE_KEY` accepts
|
|
the actual multiline PEM value from your secret manager. Never commit the PEM or
|
|
secrets. The optional Compose override `docker-compose.github-app.yml` mounts
|
|
`./secrets/github-app.pem` in both services:
|
|
|
|
```sh
|
|
docker compose -f docker-compose.yml -f docker-compose.github-app.yml up -d --build
|
|
```
|
|
|
|
Keep the existing `CLIENT_ID`, `CLIENT_SECRET`, `AUTH_CALLBACK`, `SESSION_SECRET`
|
|
and credential encryption keyring unchanged. The App adds encrypted credentials
|
|
under `github-app-user`; legacy `github` credentials remain OAuth credentials.
|
|
Refresh tokens have a distinct authenticated encryption purpose. The existing
|
|
credential verification command now checks both envelopes.
|
|
|
|
Deploy this release to all readers/workers **before** enabling App connections.
|
|
Existing records without a connection binding retain OAuth behavior; no bulk
|
|
credential migration is necessary for an already encryption-capable deployment.
|
|
Do not rerun plaintext cleanup just to enable the App.
|
|
|
|
## User flow
|
|
|
|
Sign in offers one GitHub App button and resolves existing accounts by GitHub
|
|
numeric user ID. Signing in preserves existing OAuth credentials and resource
|
|
bindings. If the App is disabled, the button uses OAuth instead.
|
|
|
|
An older account without a GitHub ID receives a one-time recovery prompt. The
|
|
user verifies the previous OAuth connection, then resumes App authorization.
|
|
Recovery is bound to the expected account and GitHub ID and expires after ten
|
|
minutes. A signed-in user cannot attach a different GitHub identity. App login
|
|
never automatically links by username or email.
|
|
|
|
On the anonymization form, **Connect read-only GitHub access** starts user
|
|
authorization and then repository installation. **Allow repository access on
|
|
GitHub** opens installation/configuration directly, preserving the current draft
|
|
in this browser tab for 30 minutes. Confirm access on GitHub and return to the
|
|
form. Existing installations have direct account-specific configuration links.
|
|
GitHub may require organization administrator approval. Use **Refresh access
|
|
after approval** on the Connections page when approval is delayed.
|
|
|
|
App-connected accounts default to the App for new repository/PR access. The
|
|
explicit **Use existing OAuth access** choice handles repositories not yet
|
|
available through the App. An App error never silently selects OAuth. Gists
|
|
continue using OAuth. An App-only user entering a gist URL is prompted to connect
|
|
OAuth, with the current repository permission scope explained. The form draft
|
|
is saved for 30 minutes and restored after authorization. Users with an existing
|
|
OAuth connection can use it immediately. OAuth remains available on the
|
|
Connections page, separate from sign-in.
|
|
|
|
**GitHub connections** lists each resource's current connection. First check
|
|
read-only access, then switch the resource. The switch validates the existing
|
|
commit or PR and conditionally updates the binding; it preserves the anonymous
|
|
URL, settings and existing content. Busy resources must finish before switching.
|
|
Each resource can be switched back to a verified existing OAuth grant.
|
|
|
|
OAuth can be explicitly revoked once all dependent resources, including gists,
|
|
have been migrated or removed and a working App sign-in remains. Merely connecting
|
|
the App does not revoke or narrow the OAuth grant.
|
|
|
|
## Access lifecycle and rollback
|
|
|
|
Installation tokens are short-lived, minted for one repository, and cached only
|
|
in process. Encrypted App user grants allow server-side renewal without a browser
|
|
session. Token refresh is serialized through MongoDB with conditional writes,
|
|
so a concurrent login or revocation cannot be overwritten. Background source
|
|
reads verify the owner's current App access; losing user access stops new reads.
|
|
App-bound resources never use the global token or another user's grant.
|
|
|
|
Uninstall, deselection, suspension and user grant revocation block new upstream
|
|
reads. Already published anonymized content follows existing expiration/removal
|
|
settings. Account removal revokes the user's grants and removes their resources;
|
|
it does not uninstall a shared organization installation.
|
|
|
|
Failed installation webhook checks remain pending in MongoDB and are retried on
|
|
the next repository access. Access stays blocked until reconciliation succeeds.
|
|
Revision checks prevent older responses from undoing newer lifecycle events.
|
|
User-revocation events verify the current grant, so delayed deliveries cannot
|
|
revoke a working grant created by reconnecting.
|
|
|
|
Set `GITHUB_APP_NEW_CONNECTIONS=false` to pause new App sign-ins/installations and
|
|
migrations while continuing to serve existing App resources. Setting
|
|
`GITHUB_APP_ENABLED=false` also disables existing App access; it does not fall
|
|
back to OAuth. After creating App bindings, rollback must stay on an App-aware
|
|
release with the same encryption keys. OAuth removal is not part of this release.
|
|
|
|
## Validation before enabling production
|
|
|
|
Run `npm test`, `npm run lint`, `npm run build`, and `npm run test:ui`.
|
|
MongoDB integration tests require a disposable test server:
|
|
|
|
```sh
|
|
TEST_MONGODB_URI=mongodb://127.0.0.1:27029 npm test
|
|
```
|
|
|
|
The tests create and drop separately named databases. Validate the configured App
|
|
against a disposable private GitHub repository: sign in, install with only that
|
|
repository selected, import, view files, refresh, migrate an OAuth resource, and
|
|
remove App access. Verify a second unselected private repository is inaccessible.
|
|
Exercise a private PR including comments and a Pages-enabled repository. Confirm
|
|
signed webhook deliveries arrive successfully and that reconnecting restores
|
|
access. Live GitHub acceptance requires a registered App and cannot be simulated
|
|
by the local test suite.
|