Skip to content
Self-hosting

GitHub App and Orb

A self-host needs webhook delivery and installation tokens. Direct GitHub App is the default, recommended model — Orb broker mode is private/managed-beta only.

Choose a connection mode

Direct GitHub App (recommended default)
Your self-host stores its own App id, slug, private key, and webhook secret, and mints installation tokens directly. No shared quota, no dependency on gittensory's own infrastructure to process a review.
Brokered Orb (private/managed-beta only)
Your self-host uses ORB_ENROLLMENT_SECRET to request short-lived installation tokens from the central Orb broker instead of holding its own App key. Not open for general public use — see the operational risks below before considering it.
Direct App mode is the public default: it costs gittensory nothing to support and can't overrun a shared rate-limit budget. Brokered mode routes every token mint through gittensory's own infrastructure and GitHub API quota — every external brokered install is gittensory's rate-limit and reliability problem, not just the operator's, so it stays private/managed-beta until the safeguards below are in place.

One-click App creation (recommended for a Direct App)

Before the App exists (no GITHUB_APP_ID set yet), the self-host serves a setup wizard at GET /setup. It renders a form that POSTs a GitHub App manifest — the exact permission and event set below, pre-filled — to GitHub's own App-creation flow. GitHub creates the App with the correct configuration in one step and redirects back to exchange credentials automatically; there is no manual permission checklist to get right or wrong. The route is disabled once an App is configured, so it can't rebind a live install.

.env
PUBLIC_API_ORIGIN=https://reviews.example.com  # exact public URL, embedded in the manifest
SELFHOST_SETUP_TOKEN=change-this-long-random-value  # unlocks /setup for a freshly-booted instance
open "https://reviews.example.com/setup?token=<SELFHOST_SETUP_TOKEN>"
bash
Manual App creation (below) is still fully supported — for an air-gapped instance, a stricter change-review process, or simply a preference for reviewing every permission by hand before it exists. Whichever path you take, the resulting App needs the SAME permissions: this doc's manual list is kept in sync with the wizard's manifest and checked in CI, so the two can't silently drift apart.

Direct App permissions

  • Pull requests: write.
  • Checks: write — the gate posts a check-run; checks: read alone 403s that write (silently fails the first review with no obvious cause).
  • Issues: write.
  • Contents: write — required for BOTH merging and the auto-maintain update_branch action. contents: read looks sufficient at creation time but silently breaks auto-merge later with no error surfaced in the UI; there is no lesser permission that keeps merge/update-branch working.
  • Commit statuses: read.
  • Metadata: read.
  • Actions: write — lets a repo opt into cancelling a closed PR's in-flight CI runs (the contributorCapCancelCi setting). Off by default and never required: a repo that doesn't enable it, or an installation that hasn't re-approved this permission on an existing App, sees no behavior change — the cancellation attempt is skipped and logged, never blocking the close itself.

Events: pull request, pull request review, push, issues, check suite, check run, and status.

Re-approving a permission bump on an existing App

A future release can widen this permission list (most recently, Actions: write for the opt-in CI-cancellation feature). GitHub does not silently grant a new permission to an App that's already installed — the operator who owns the App must explicitly re-approve it, the same one-time consent step as the original install.

Until you re-approve, the self-host keeps working exactly as before: any feature that needs the new permission degrades gracefully (skipped and logged, never a hard failure) rather than erroring. There's no forced upgrade window.

To re-approve:

  1. Open your App's settings page — https://github.com/settings/apps/<your-app-slug>/permissions (organization Apps: https://github.com/organizations/<org>/settings/apps/<your-app-slug>/permissions).
  2. GitHub shows a diff between the App's currently-granted permissions and what the App manifest now requests. Review it, then save — GitHub sends the installation owner a request to accept the new grant.
  3. Accept the request (as the installation owner, on each installed org/account). The new permission takes effect immediately; no App reinstall or webhook resubscription needed.

Direct App env

.env
GITHUB_APP_ID=123456
GITHUB_APP_SLUG=my-gittensory-app
GITHUB_APP_PRIVATE_KEY_FILE=/run/secrets/github-app-private-key.pem
GITHUB_WEBHOOK_SECRET=<same-secret-configured-on-the-app>

Telemetry is separate from token brokerage

These are two independent things people conflate because they're both "Orb": anonymized fleet-calibration telemetry export (enabled by default, works in either connection mode) and token brokerage (optional, private/managed-beta only, lets your self-host get installation tokens from gittensory instead of holding its own App key). Choosing Direct App mode does not opt you out of telemetry, and it's what makes the homepage counters and cross-fleet gate calibration reflect direct installs, not just brokered ones.

What's exported
Per resolved PR: the gate verdict, the realized outcome (merged/closed), a reversal flag, a bucketed reason category, and cycle time.
What's never exported
Repo/owner/PR names, commit SHAs, source code, diffs, comments, or logins. Repo/PR identifiers are HMAC-anonymized with a per-instance secret gittensory's own collector never holds.
Disabling it
Set ORB_AIR_GAP=true to compute everything locally and send nothing — the only supported opt-out. There is no partial opt-out short of air-gapping.

Brokered Orb env

.env
ORB_ENROLLMENT_SECRET=<issued-once-by-orb>
ORB_BROKER_URL=https://gittensory-api.aethereal.dev
Brokered mode is useful when the self-host should not hold a GitHub App private key. It still needs a reachable webhook path or relay mode, depending on the network setup.
Brokered mode operational risks
Before enabling this for anyone outside a controlled managed-beta cohort, weigh: (1) rate-limit blast radius — every brokered install's GitHub API traffic draws from token pools gittensory manages, so one misbehaving or high-volume install can degrade every other brokered install; (2) quota management — there is no automatic per-install cap on how much of that shared budget one enrollment can consume; (3) support burden — a broken brokered install looks like a gittensory outage to its operator, not a self-host misconfiguration, and lands as a support request on gittensory directly; (4) abuse/misconfiguration risk — an enrollment secret that leaks or a misconfigured relay can mint tokens or receive webhook traffic for repos the intended operator doesn't control.

Minimum broker safeguards before a public rollout

A maintainer go/no-go checklist — do not open brokered enrollment beyond a small, known, controlled cohort until every item below is true:

  • Enrollment quota — a hard cap on how many brokered installs can be active at once, not just an informal agreement.
  • Per-install concurrency limit — one brokered install cannot occupy an unbounded share of the token-minting or webhook-relay pipeline.
  • Per-install rate budget — a ceiling on GitHub API calls attributable to a single enrollment, independent of the other installs sharing the broker.
  • Revocation path — an enrollment secret can be revoked immediately, without waiting for a deploy, when it's compromised or the install is abusive.
  • Metrics broken out by enrollment — token-mint volume, webhook-relay volume, and error rate are visible per-enrollment, not only aggregated across every brokered install, so one bad actor is identifiable instead of hiding in the average.

See Troubleshooting for what a degraded brokered relay looks like in logs today, and the beta release checklist's brokered-mode scenario for the smoke test that exercises this path.

Webhook checks

curl https://reviews.example.com/health
curl https://reviews.example.com/ready
bash

After installing the App on a test repo, open a small PR and confirm the webhook delivery appears in GitHub and a job appears in self-host logs. Continue with Operations for log and metric checks.