Epic 13 — Admin · GitHub App & Secrets
Covers GitHub App install status, app_id / installation_id surfacing, scope and permission checks, GitHub App auth-failure detection and remediation, and a concrete PEM rotation wizard that walks the Operator through the documented manual provisioning flow. Infisical was evaluated and rejected; this flow is intentionally manual. No PEM byte or base64 string is ever entered into or transmitted from the browser UI.
Personas: OP (exclusive — all stories)
Shared modules:
CorrelationChip
EnvProvenance
Story 13.1 — View GitHub App Install Status
- As an
- OP
- I want
- to see the current GitHub App installation status, configured
app_id, andinstallation_id - So that
- I can verify the App is correctly installed and scoped to the target organisations
Scenario: GitHub App healthy — status panel renders
Giventhe Operator navigates to
/admin/github-app
WhenGET /admin/github-app/status resolves with status: "healthy"
Thenthe status panel shows: a green Healthy badge, app_id and installation_id (masked after the first 4 chars), the list of organisations the App is installed on, and the App's granted permission scopes (contents: read, pull_requests: write, metadata: read)
Scenario: GitHub App not installed — CTA shown
When
GET /admin/github-app/status returns status: "not_installed"
Thenan amber Not installed badge is shown and an Install GitHub App button links to the GitHub App installation URL
| Endpoint / DB | Purpose |
|---|---|
GET /admin/github-app/status | Returns status, app_id, installation_id, orgs, scopes |
Story 13.2 — Scope and Permission Check
- As an
- OP
- I want
- to see a warning if the GitHub App is missing required permissions
- So that
- I can re-configure the App before a run fails due to insufficient access
Scenario: All required permissions granted — no warning
Giventhe App has
contents: read, pull_requests: write, and metadata: read
Theneach permission is listed with a green Granted indicator
Scenario: Missing permission — amber warning with remediation link
Giventhe App is missing
pull_requests: write
Thenthe pull_requests: write row shows an amber Missing badge and a remediation link reads Update App permissions on GitHub linking to the App settings page (new tab)
Story 13.3 — GitHub App Auth-Failure Detection
- As an
- OP
- I want
- the admin panel to detect and flag when the GitHub App JWT exchange is failing
- So that
- I am alerted before all run triggering begins failing across the platform
Scenario: Auth failure detected — remediation prompt
Given
GET /admin/github-app/status returns status: "auth_failure"
Whenthe Operator views the GitHub App admin page
Thena red Auth failure banner reads: GitHub App JWT authentication is failing. The private key may have expired or been revoked.; a Begin PEM rotation button links to Story 13.4; CorrelationChip shows the request_id from the last failed attempt
Scenario: Intermittent failure — amber Degraded badge
Given
GET /admin/github-app/status returns status: "degraded" (recent auth failures below total-failure threshold)
Thenan amber Degraded badge is shown with the error rate and a recommendation to monitor
Story 13.4 — PEM Rotation Wizard
- As an
- OP
- I want
- a step-by-step wizard to guide me through rotating the GitHub App private key
- So that
- I can restore GitHub authentication without referring to external documentation
Wizard step 1 — Generate new private key on GitHub
ThenStep 1 copy reads: Navigate to your GitHub App settings → Private keys → Generate a private key. Download the
.pem file to your local machine. An Open GitHub App settings link (new tab) and a Mark as done button are provided.
Wizard step 2 — base64-encode the key locally
ThenStep 2 shows a code block with:
base64 < /path/to/your-key.pem. Copy explicitly instructs the user to set this as the GH_APP_PRIVATE_KEY_B64 secret in their deployment environment. No input field accepts a PEM or base64 key value.
Wizard step 3 — Update secret in deployment environment
ThenStep 3 instructs: In your GitHub repository: Settings → Environments →
dev → Secrets → GH_APP_PRIVATE_KEY_B64. Replace the value. An Open repository secrets link (new tab) is provided.
Wizard step 4 — Re-run deploy job
ThenStep 4 instructs: Re-run the deploy workflow so the runner host writes the new key to
secrets/github_app_key.pem on the target host. A link to the CI/CD docs is provided.
Wizard step 5 — Restart amtp-github-mcp service
ThenStep 5 shows:
docker compose restart amtp-github-mcp (dev) or equivalent for the environment. A Proceed to verification button advances to Story 13.5. On completion, an Epic 15 audit-log entry github_app_key_rotated is written with no key bytes.
| Endpoint / DB | Purpose |
|---|---|
| None | Wizard is informational only; no AMTP API mutation during steps 1–5; rotation is performed out-of-band |
POST /audit/events | Wizard completion writes Epic 15 audit entry (no key bytes) |
Story 13.5 — Post-Rotation Verification
- As an
- OP
- I want
- to run a healthcheck after completing the PEM rotation wizard
- So that
- I can confirm the new key is accepted by GitHub before closing the incident
Scenario: Verification passes — green result
Whenthe Operator clicks Verify connection
Then
POST /admin/github-app/verify is issued; a progress indicator is shown; on success a green callout reads Connection verified — GitHub App authenticated; an audit-log entry github_app_key_rotation_verified is written with no key material
Scenario: Verification fails — failure callout with retry
When
POST /admin/github-app/verify returns a non-200 response
Thena red Verification failed callout shows the error summary with CorrelationChip; a Retry verification button and a Re-open rotation wizard link (back to step 4 of Story 13.4) are offered
| Endpoint / DB | Purpose |
|---|---|
POST /admin/github-app/verify | Trigger a test JWT exchange; returns pass/fail |