# GitHub App review connector

**Status: local GitHub installation, repository selection, exact-patch draft-PR approval, and read-only check-run lookup are implemented against fake-provider fixtures; no GitHub App is registered or deployed.** The Connectors dashboard has owner/admin install and disconnect controls, workspace-scoped status, metadata-only repository browsing, and a single selected repository. Its callback is bound to encrypted, single-use state, a live SiteWatch session, a short-lived HttpOnly/Secure/SameSite=Lax browser cookie, and PKCE. It verifies the setup URL's `installation_id` against the authorizing user's App installation list before storing that installation ID in a tenant-scoped table. The transient AI patch review offers a separate explicit action to create a branch and draft PR for the selected repository; it checks the exact replacement hash and current remote source hash and never merges. After creation, an administrator can separately confirm a one-time read of at most 100 check runs for that exact PR head SHA. Results are returned without raw output or provider links and are not retained; a changed head is rejected. This reports observed check runs only and does not prove they are required or satisfy branch protection. The [adapter](../connectors/github/draft-pr.mjs) uses short-lived repository-scoped tokens and reconciles same-request retries. The HTTP fixtures use fake GitHub transport; no live GitHub request was made. The local repair connector remains a separate path.

## Proposed permission boundary

Use a GitHub App installed only on repositories the workspace owner selects. The App should request repository `Contents: write` to create a commit on a new branch and `Pull requests: write` to open a draft PR. Repository metadata is required to identify the selected repository. Do not request administration, actions/workflows, checks, issues, deployments, organization, or account permissions in the first version. GitHub documents that App permissions are selected explicitly and recommends requesting the minimum needed.

At token creation, request only the selected repository ID and reduce the installation token to `contents: write` and `pull_requests: write`. Do not use a customer-wide PAT. Keep the App private key in the SiteWatch server's secret store, never in a browser, connector report, source bundle, prompt, or customer workspace export. Generate an RS256 App JWT with `iat` about 60 seconds in the past and `exp` no more than ten minutes ahead; exchange it for the repository-scoped installation token, which expires after one hour. Do not persist that installation token; mint it when needed and discard it after the operation.

## Safe draft-PR flow

1. An owner or administrator explicitly starts GitHub App installation from the authenticated workspace. SiteWatch opens `https://github.com/apps/{slug}/installations/new`; the GitHub App setup URL and OAuth callback are both configured as `PUBLIC_URL/api/github/callback`. Do **not** enable GitHub's “Request user authorization (OAuth) during installation” option for this two-step flow, because GitHub then bypasses the setup URL. GitHub's setup URL includes an untrusted `installation_id`; SiteWatch requires the initiating browser's short-lived callback cookie and encrypted, one-time state, then sends the user through OAuth with a PKCE S256 challenge. It exchanges the code using the stored verifier, uses the temporary expiring user token to list that user's App installations, and only links the installation if the ID is present. Discard both access and refresh tokens immediately. The local flow, status/disconnect route, metadata-only repository listing, and owner/admin single-repository selection are implemented.
2. The owner asks for one AI source-file patch. Keep the current per-request source consent, workspace AI consent, secret screening, bounded file size, and exact before/after SHA-256 review.
3. A separate checkbox and button in the exact patch review authorizes opening a draft PR in the selected repository. SiteWatch checks the submitted replacement against its reviewed after-hash, then re-reads the base branch and source file. Abort if the current branch head or file SHA-256 differs from the reviewed evidence.
4. Create a unique SiteWatch branch from the exact base commit, commit only the reviewed file replacement, and open a **draft** PR with the evidence, test status, risk, rollback and source-finding links. Do not merge, push to the base branch, or edit `.github/workflows/**`. A PR is a review request, not a verified repair.
5. Show the resulting PR URL and immutable commit SHA. Read CI/check results only after separately approved read access is designed. Do not tell the owner that tests passed unless repository checks report success for that exact head SHA. Keep a bounded per-workspace request budget and deduplicate retries; an ambiguous create response must be reconciled by branch/head before retrying.
6. Uninstalling the App in GitHub is what revokes provider access. SiteWatch's local disconnect only removes its installation link and audits that action; it does not uninstall the App in GitHub. The signed webhook endpoint now processes `installation` suspend, unsuspend, and deleted events, and `installation_repositories` removals. Suspension pauses all local repository operations; uninstall deletes matching installation links; repository removal clears matching selected repositories. If GitHub reports an access-removal event without repository IDs, SiteWatch clears the local selections for that installation and requires an administrator to select again. Delivery IDs are retained indefinitely and deduplicated; raw payloads are never retained. The small delivery ledger is retained indefinitely because GitHub's HMAC signature does not carry a timestamp that would make later replay distinguishable. Never automatically delete a remote branch or PR during disconnect.

GitHub's REST API documents that updating repository contents requires `Contents: write`, while creating a pull request requires `Pull requests: write`. Installation tokens can be limited to specified repository IDs and permissions and expire after one hour. These permissions still allow writing content on the selected repository; branch protection, pull-request review requirements and required checks must remain enabled in that repository. SiteWatch must not claim branch protection is configured unless it reads and validates the relevant repository rules.

## Optional read-only check-run inspection

The draft-PR review can request a one-time read of the check runs attached to the exact commit SHA returned when the draft PR is created. This is a separate action and checkbox from creating the PR. SiteWatch re-fetches the PR from the selected repository, verifies both repository IDs and rejects the request if the head SHA has changed, then requests a short-lived installation token scoped to that repository with `Checks: read` and `Pull requests: read`. The App installation must grant these additional read permissions; if GitHub denies access, SiteWatch returns no provider body or credential. No check output, links, or names are stored in the database or audit record.

The display describes returned check-run state as passed, failed, pending, partial, or no checks. It does **not** establish which checks are required, read legacy commit statuses, validate branch protection, or say that a PR is safe to merge. It returns at most 100 check runs; additional runs produce a partial result. The owner must inspect GitHub's protected-branch and required-check settings directly.

## Current limits and release gates

- A public HTTPS SiteWatch origin and registered GitHub App are required for production. The flow intentionally refuses HTTP, localhost, and `*.ts.net` origins, including the current private Tailscale address.
- Configure `GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_CLIENT_ID`, `GITHUB_APP_CLIENT_SECRET`, `GITHUB_APP_SLUG`, `GITHUB_APP_CALLBACK_URL`, and a unique high-entropy `GITHUB_APP_WEBHOOK_SECRET` on the server. The callback URL must exactly match the configured public HTTPS origin plus `/api/github/callback`; GitHub's Setup URL must be that same callback. Set the GitHub App webhook URL to `https://<public-origin>/api/github/webhook`, paste the same secret into the GitHub App registration, and enable the webhook. GitHub delivers installation and installation-repositories events by default; no manual event subscription is needed for these two event types. The callback URL is not the webhook URL. Enable expiring user tokens. Keep GitHub's OAuth-on-install option off so its setup URL receives the installation ID.
- The owner/admin connection API, callback flow, tenant-scoped installation record, dashboard install/disconnect controls, metadata-only repository enumeration, selected-repository persistence, exact-patch draft PR consent UI/route, signed webhook revocation handling, one-time exact-head read-only check-run lookup, and audit events are implemented and tested with fake provider traffic. Optional `Checks: read` and `Pull requests: read` permissions must be granted to use the status lookup. GitLab/Bitbucket/Azure DevOps/Gitea adapters and live provider tests remain open.
- Current fake-provider fixtures cover installation authorization and PKCE, tenant/session/browser binding, install/disconnect roles, single-repository token narrowing, exact source hash revalidation, path restrictions, stable retry reconciliation, bounded responses, secret redaction, webhook HMAC validation, duplicate delivery handling, suspension/resumption, repository access removal, and uninstall cleanup. These do not replace the pending real private-repository, real webhook, CI-status, hosted-rate-limit, or provider interoperability acceptance.
- Acceptance requires a disposable private repository with branch protection, required CI, and the optional read permissions. Verify a clean draft PR, exact-head check-run states, changed-head refusal, stale patch refusal, revoked installation, network timeout/retry, and no writes to the base branch. The PR stays open until a repository owner merges it.
- Keep the existing local repair connector and manual coding-prompt path available. GitHub is the first provider proposal, not a claim that every source host or application runtime is covered.

## Official GitHub references

- [Choosing GitHub App permissions](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app)
- [GitHub App setup URL and installation ID spoofing warning](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/about-the-setup-url)
- [GitHub App web application flow, state, and PKCE](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app)
- [List installations accessible to an authorized user](https://docs.github.com/en/rest/apps/installations#list-app-installations-accessible-to-the-user-access-token)
- [List repositories accessible to an App installation](https://docs.github.com/en/rest/apps/installations#list-repositories-accessible-to-the-app-installation)
- [Generate a JSON Web Token for a GitHub App](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app)
- [Create an installation access token](https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app)
- [Create or update repository contents](https://docs.github.com/en/rest/repos/contents#create-or-update-file-contents)
- [Create a pull request](https://docs.github.com/en/rest/pulls/pulls#create-a-pull-request)
- [List check runs for a Git reference](https://docs.github.com/en/rest/checks/runs#list-check-runs-for-a-git-reference)
- [Create a repository-scoped installation token](https://docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app)
- [Using webhooks with GitHub Apps](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/using-webhooks-with-github-apps)
- [Validating webhook deliveries](https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries)
- [GitHub App installation and installation-repositories webhook events](https://docs.github.com/en/webhooks/webhook-events-and-payloads)

Docs reviewed October 26, 2026. GitHub specifies the token and permission behaviors; the flow and release gates above are SiteWatch design requirements derived from them.
