OPER-158
OPER-9C-CUTOVER: Dispatcher cutover from GH_DISPATCH_PAT to GitHub App installation-token auth
Suggested
Justin Cooke
Body
## Context
OPER-9C human-gate steps are complete: GitHub App created, installed on portico + operant-studio + piperdx, and secrets `GITHUB_APP_ID`, `GITHUB_APP_INSTALLATION_ID`, `GITHUB_APP_PRIVATE_KEY` are set on `operant-studio-web` across Production, Preview, and Development. Production redeployed 2026-09-09T14:55Z.
The dispatcher must now cut over from `process.env.GH_DISPATCH_PAT` to the GitHub App installation-token mint. This ticket produces the cutover PR.
**Rollback path:** `GH_DISPATCH_PAT` stays defined in Vercel and as a fallback in the codebase for one week after cutover. If canary dispatch fails, revert the PR and dispatcher automatically falls back.
**Ledger category:** `ASSURE-DISPATCHER-AUTH`
**Depends on:** OPER-9C (unblocked — human gate confirmed)
**Blocked by:** none
## Goal
Replace PAT-based GitHub auth in the dispatcher with GitHub App installation-token auth, verified by a canary dispatch, without disrupting the live fleet.
## Acceptance Criteria
- **Done when:**
- `@octokit/auth-app` dependency added to the dispatcher package (whichever workspace owns `tools/dispatcher` or the equivalent in `operant-studio`)
- Dispatcher reads `GITHUB_APP_ID`, `GITHUB_APP_INSTALLATION_ID`, `GITHUB_APP_PRIVATE_KEY` from env and mints an installation access token via `@octokit/auth-app`
- Installation token is cached in-memory per dispatcher invocation and refreshed when <5 min from expiry (GitHub tokens live 60 min)
- Existing PAT read (`process.env.GH_DISPATCH_PAT`) preserved as fallback path, wrapped in a feature flag `DISPATCH_AUTH_MODE` (values: `app` | `pat`, default `app`)
- One canary dispatch (any `PLANNING_VALIDATED` ticket the dispatcher would otherwise pick up next) succeeds under `DISPATCH_AUTH_MODE=app`, evidenced by a GitHub Actions run whose `auth_mode` output line reads `app`
- PR body documents the rollback path (flip env var to `pat`) and the removal timeline (one week from merge, tracked in a follow-up ticket)
- **Self-test:**
- Unit test: mint a token with a mocked private key; assert `Authorization: token ghs_...` header shape
- Integration test: dispatcher spawned with `DISPATCH_AUTH_MODE=app`, mocked GitHub API returns 200 for `POST /repos/{owner}/{repo}/actions/workflows/{workflow}/dispatches`; assert exactly one call was made and the `Authorization` header contains an installation token, not a PAT
## Constraints
- PR size: L or smaller. If the change exceeds L, split into (1) auth abstraction + tests, (2) dispatcher wiring, (3) canary evidence.
- No PHI touched; no schema changes; no RLS impact — this is auth-plane only.
- Do NOT delete `GH_DISPATCH_PAT` from Vercel or the codebase in this PR. Removal is a separate follow-up ticket after one week of green canary + fleet dispatches under `app` mode.
## Provenance
Filed by user:justin after completing OPER-9C human gate. See OPER-9C for the human-side setup evidence.
---
<!-- admission-rejected -->
**Admission rejected (missing_feature_id):** ticket body is missing `feature_id: FEAT-...` frontmatter — declare which feature this ticket implements
Attachments
Loading attachments…
Comments
Loading comments…