Skip to content

feat(github-app): P4.1 — install flow + installation token minter, flag-OFF#224

Merged
mastermanas805 merged 3 commits into
masterfrom
feat/github-app-p4-1-2026-06-03
Jun 3, 2026
Merged

feat(github-app): P4.1 — install flow + installation token minter, flag-OFF#224
mastermanas805 merged 3 commits into
masterfrom
feat/github-app-p4-1-2026-06-03

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

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

…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>
@mastermanas805 mastermanas805 enabled auto-merge (squash) June 3, 2026 13:49
mastermanas805 and others added 2 commits June 3, 2026 19:33
…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>
@mastermanas805 mastermanas805 merged commit 1c195e4 into master Jun 3, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant