feat(github-app): P4.1 — install flow + installation token minter, flag-OFF#224
Merged
Merged
Conversation
…ag-OFF
First slice of the GitHub App layer (P4) on top of the existing manual per-repo
webhook: a team installs the InstaNode App once instead of pasting a webhook
into each repo, and private-repo clones can use short-lived, least-privilege,
server-minted installation tokens instead of a long-lived PAT. Gated by
GITHUB_APP_ENABLED (default false) → /integrations/github/{install,callback}
return 501 github_app_disabled until the operator registers the App
(infra/GITHUB-APP-RUNBOOK.md). Manual webhook + source=git remain unchanged.
- config: GitHubAppEnabled flag + GITHUB_APP_{ID,SLUG,PRIVATE_KEY,WEBHOOK_SECRET,
CLIENT_ID,CLIENT_SECRET} (operator k8s secrets) + default-OFF/true/plumbing tests.
- migration 066: github_installations (installation_id PK ↔ team) + testhelpers DDL.
- internal/github: App token minter — RS256 App-JWT (≤10m) → POST
/app/installations/{id}/access_tokens (contents:read, ~1h), Redis-cached ~55m,
never persisted at rest. Injectable HTTP client + clock; 100% covered (mocked
GitHub + miniredis cache + all error arms).
- models: github_installations CRUD (upsert/get/list/suspend/delete), sqlmock-tested.
- handlers: GET /integrations/github/install (RequireAuth → 302 to the App page
with a signed anti-CSRF state) + /callback (state-verified → persist link →
302 to dashboard). HS256 state sign/verify (100% covered) + DB-gated handler
integration tests (flag-off 501, misconfigured 503, install 302, callback
invalid-state/invalid-id/happy-persist).
- agent_action entries for the new codes; router + testhelpers wiring.
Token minting into the source=git clone path + the App webhook (push→auto
redeploy) are P4.2. Contract sync (openapi/llms/MCP) + dashboard UI are P4.3,
deferred to flag-on (as with P2/P3).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…back) CI patch-coverage flagged github_app.go handler arms the routed integration tests can't reach. Add a signInstallStateFn seam + white-box tests for the no-team guard (RequireAuth normally guarantees a team), the unreachable state-sign error, and the Callback disabled-feature return; plus DB-gated integration tests for the callback invalid-team-UUID (parseTeamID) and persist-error (team_id FK violation) arms. All github_app.go branches now exercised (white-box locally + integration in CI). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two registry-iterating contract tests caught the new surface: - agent_action for github_app_disabled referenced a bare /api/v1 path; switch to the canonical https://api.instanode.dev/api/v1/... host (TestAgentActionContract_APIPathsUseAPIHost). - the new /integrations/github/{install,callback} routes are registered but flag-gated OFF (501 until P4.3), so documenting them in the agent-facing OpenAPI now would mislead agents — whitelist them in the route-coverage gate with justification (contract sync lands at flag-on, P4.3), matching the /auth/exchange precedent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First slice of the GitHub App layer (P4) on top of the existing manual per-repo
webhook: a team installs the InstaNode App once instead of pasting a webhook
into each repo, and private-repo clones can use short-lived, least-privilege,
server-minted installation tokens instead of a long-lived PAT. Gated by
GITHUB_APP_ENABLED (default false) → /integrations/github/{install,callback}
return 501 github_app_disabled until the operator registers the App
(infra/GITHUB-APP-RUNBOOK.md). Manual webhook + source=git remain unchanged.
CLIENT_ID,CLIENT_SECRET} (operator k8s secrets) + default-OFF/true/plumbing tests.
/app/installations/{id}/access_tokens (contents:read, ~1h), Redis-cached ~55m,
never persisted at rest. Injectable HTTP client + clock; 100% covered (mocked
GitHub + miniredis cache + all error arms).
with a signed anti-CSRF state) + /callback (state-verified → persist link →
302 to dashboard). HS256 state sign/verify (100% covered) + DB-gated handler
integration tests (flag-off 501, misconfigured 503, install 302, callback
invalid-state/invalid-id/happy-persist).
Token minting into the source=git clone path + the App webhook (push→auto
redeploy) are P4.2. Contract sync (openapi/llms/MCP) + dashboard UI are P4.3,
deferred to flag-on (as with P2/P3).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com