16 KiB
spec, created, amended, status
| spec | created | amended | status |
|---|---|---|---|
| docs/specs/integrations/github-authentication.md | 2026-07-19 | 2026-07-21 | draft |
Implementation Plan: Workspace GitHub Authentication
Overview
Tasks 01-10 delivered workspace PAT/CLI/App-installation routing, personal identity, renewable executor credentials, and workspace-aware services. Tasks 11-16 delivered an unpublished singleton GitHub App registration. This amendment replaces that singleton with a registration catalog chosen per workspace, adds import/create/select onboarding, moves the UX out of System Settings, and makes callbacks, webhooks, runtime clients, and personal OAuth registration-aware.
The branch is eight commits behind and nineteen commits ahead of origin/main. Resolve the known
merge conflict first, then rewrite the unpublished schema before building dependent runtime and UI
layers. Released legacy_shared migration behavior remains unchanged.
Architecture
github_app_registrations is a deployment catalog, not a global active identity. Every registration
is manifest-created or imported and has an encrypted generation bundle. A workspace App connection
stores both registration ID and installation ID. Reusing a registration is explicit and shares
root App credentials; separate registrations provide independent work/personal trust boundaries.
The manifest flow preallocates a registration UUID so all generated callback and webhook URLs are registration-specific. Import verifies an existing App before publishing it to the catalog. Runtime clients are resolved from a registry keyed by registration ID and generation. Webhook paths select one candidate registration and verify its HMAC before parsing or deduplicating.
Conflict Resolution
Merge the latest origin/main before production edits. Resolve the current conflict as follows:
apps/web/components/github/github-settings.tsx: preserve upstream repository-scope UI behavior, then keep workspace-keyed GitHub auth wiring. Do not preserve the singleton System Settings handoff because Task 18 replaces it.
apps/web/e2e/helpers/api-client.ts and docs/specs/INDEX.md currently auto-merge. Confirm their
upstream additions and this branch's GitHub authentication entries are both retained after merging.
Do not resolve conflicts by checking out either side wholesale. Confirm git ls-files -u is empty
and run frontend typecheck before Task 12.
Backend
Registration Persistence
Rewrite the unpublished singleton DDL in apps/backend/internal/github/store.go:
- replace
github_app_registrationwith pluralgithub_app_registrationsand the fields in the spec; - replace singleton flow-head state with workspace-bound flows carrying a preallocated registration ID;
- add
app_registration_idconstraints/FKs to workspace connections, user connections, and auth flows; - make webhook delivery identity composite by registration;
- retain the released old-workspace
legacy_sharedseeding path, but add no migration from the unpublished singleton tables.
Replace deployment_app_store.go with registration-ID repository operations. Secret IDs are
registration/generation-specific and deletion is restricted by all workspace and personal
references. Remove the unpublished GitHubAppConfig, KANDEV_GITHUB_APP_* bindings, singleton
source resolver, and configuration tests; there is no compatibility registration or fallback.
Create And Import Protocol
Generalize deployment_app_manifest.go and deployment_app_conversion_client.go around a
preallocated registration ID. Generated webhook, redirect, setup, and OAuth callback URLs include
that ID. The manifest visibility is user-selected and private by default. Preserve exact
permission/event policy, owner-specific GitHub submission endpoints, one-hour single-use state,
public-origin validation, response bounds, and secret-safe errors.
Add an import verifier that accepts bounded credential material, builds an App JWT, verifies
GET /app identity/owner/slug, validates the configured callback/webhook policy as far as GitHub's
API exposes it, and atomically stores only after verification. Missing settings become actionable
diagnostics; duplicate host/App ID returns the known registration ID.
Runtime Registry
Replace the one DeploymentAppRuntime generation in service_app_auth.go,
deployment_app_config.go, and backend application wiring with a concurrency-safe registry keyed
by registration ID. Loading or invalidating one registration must not swap another. Include
registration ID/generation in installation-token cache, resolver principal, credential broker, and
singleflight keys. Runtime App auth resolves only catalog records loaded from encrypted bundles.
Startup independently loads every valid catalog entry, reports invalid entries without preventing PAT/CLI startup, reconciles orphan secret bundles, and hot-adds a successfully created/imported registration without restarting Kandev.
Webhook Routing
Change webhook handling to accept a route registration ID. Load exactly one webhook secret, verify
HMAC, then parse and claim (registration_id, delivery_id). Installation/repository/user events may
only mutate workspace/personal rows whose registration ID and external installation/user identity
match. Registration-specific valid failures update only that registration's health.
Workspace App Lifecycle API
Replace deployment singleton controllers/services with catalog list, manifest start/callback, import, rename, and guarded delete endpoints. Installation start accepts registration ID; install and personal callbacks verify the route ID against hashed flow state. A successful installation atomically swaps workspace connection/generation and deletes incompatible personal secrets; failure leaves current auth active.
Extend status, mocks, E2E reset, and stable error mapping. Remove /settings/system/github-app
callback redirects and return to /settings/integrations/github?workspace_id=.... Registration API
responses expose metadata, source, health, selection, and sharing warnings but no secret or
conversion code.
Frontend
API, Types, And State
Replace deployment singleton types/hooks with registration catalog contracts in
apps/web/lib/types/github.ts, lib/api/domains/github-auth-api.ts, and
hooks/domains/github/. Catalog queries are workspace-keyed. Add create-manifest, import, rename,
delete, select/install operations and stable callback-result parsing. Remove the System Settings
route, sidebar entry, page, and deployment-only hook/components.
Workspace status carries selected registration metadata. Changing active workspace clears catalog, status, actor, health, and in-progress form state before refetch so no prior workspace identity flashes.
Workspace Authentication UX
Refactor github-connection-dialog.tsx into a method list rather than segmented tabs. PAT and CLI
keep focused forms with matched control heights. GitHub App first explains use cases and trade-offs,
then offers known registrations, Add existing App, and Create new App. Selection leads to an
explicit installation handoff; importing/creating alone never changes workspace auth.
Move owner, public URL, permission dialog, manifest submission, and callback status UI from System Settings into workspace GitHub settings. Add the imported-App instruction/form flow with exact copyable URLs, GitHub settings locations, required permissions/events, bounded secret inputs, and validation. Visibility defaults private and explains public installability versus Marketplace and repository grants. Known shared registrations disclose their shared root identity/revocation boundary.
Workspace automation copy accurately distinguishes Kandev-managed automation from unmanaged
executor overrides. Permission chips become one details button/dialog. My GitHub identity is
connectable only for App automation; PAT/CLI show that their verified human automation identity is
also used for personal actions without presenting a selector.
Mobile Contract
Desktop and mobile use the same catalog and forms. Mobile presents method selection and onboarding as a single-column page/sheet with one scroll owner, safe-area spacing, 44px controls, no fixed footer, and no horizontal overflow. Copyable URLs and long App names wrap; secret fields and primary actions never overlap. External GitHub navigation returns to the initiating workspace route.
Tests
deployment_app_store_test.go(renamed as appropriate): multiple registrations, secret-generation compensation, per-registration deletion restriction, restart reload, and no singleton migration.store_connections_test.goandpersonal_connection_repository_test.go: registration FK invariants, atomic connection switch, personal token deletion, generation revocation, workspace delete, copy exclusion, and released legacy migration.deployment_app_manifest_test.goand conversion/import tests: route-specific URLs, default private and explicit public manifests, owner URLs, exact policy, state replay/expiry, response bounds, duplicate import, GitHub identity mismatch, and no secret errors.service_app_auth_test.go, resolver, token-cache, and broker tests: concurrent different registrations, intentional reuse, hot add/invalidate, registration-keyed caches, and no cross-registration fallback.webhook_service_test.go: wrong route/signature, composite dedupe, matching registration plus installation, health isolation, suspension/deletion/repository changes, and personal revocation.- Controller/service tests: catalog CRUD, create/import/install callbacks, stale flow, guarded delete, status metadata, mock/reset isolation, and secret-free JSON.
- Frontend unit tests: workspace switching, method comparison, known registration selection, import/create validation, private/public disclosure, permissions dialog, callback outcomes, matched control heights, and conditional personal identity.
E2E Tests
Update the GitHub authentication suites rather than retaining System Settings registration tests:
- workspace A creates a private App and workspace B imports another App; each status and installation remains isolated;
- two workspaces intentionally select the same known registration and show the shared-root warning while retaining different installation/repository status;
- creation/import cancellation and invalid/replayed callbacks preserve current automation;
- switching Apps removes incompatible personal identity;
- desktop and mobile complete PAT, CLI, select, import, create, install, and permissions flows with no clipping, overlap, or horizontal overflow.
Real GitHub staging remains necessary for one manifest conversion, imported-App verification, installation, OAuth, and correctly signed webhook delivery.
Public Documentation
Update docs/public/integrations.md and docs/public/configuration.md for method choice,
registration reuse versus strict isolation, import/create instructions, private/public meaning,
callback/webhook paths, and permissions/events. Delete the unpublished App environment variables and
instructions rather than documenting them as a supported path. Reconcile docs/ARCHITECTURE.md,
apps/backend/AGENTS.md, feature coverage metadata, and screenshots/terminology that still claim
one deployment App or System Settings ownership.
Implementation Waves
Tasks 01-10 remain completed implementation history for the workspace credential foundation. Superseded singleton Tasks 11-16 are replaced by the pending tasks below.
Completed Workspace Credential Foundation
- Task 01: Persistence and legacy migration - done
- Task 02: GitHub App token primitives - done
- Task 03: Workspace PAT and CLI resolver - done
- Task 04: App installation and personal OAuth lifecycle - done
- Task 05: Workspace-aware service routing - done
- Task 06: Renewable executor credentials - done
- Task 07: Connection API, health, and mocks - done
- Task 08: Workspace and personal settings - done
- Task 09: Initial E2E and public docs - done
- Task 10: Initial QA and security - done
Wave 0: Reconcile Main
Wave 1: Persistence Contract
Wave 2: Onboarding Protocol
Wave 3: Registration-Aware Runtime (parallel)
Task 14 owns runtime clients, resolver, caches, and broker files. Task 15 owns webhook service and delivery persistence. They share only Task 12 models and can run independently after Task 13.
Wave 4: Backend API
Wave 5: Frontend Contract
Wave 6: Workspace UX
Wave 7: Product Proof (parallel)
Task 19 owns Playwright fixtures/specs. Task 20 owns public and architecture documentation.
Wave 8: Integrated Review
Final Verification
Run formatting before lint:
rtk make -C apps/backend fmt
rtk make -C apps/backend test
rtk make -C apps/backend lint
cd apps/web && rtk pnpm run typecheck
cd apps && rtk pnpm --filter @kandev/web test
cd apps && rtk pnpm --filter @kandev/web lint
cd apps/web && rtk pnpm e2e:run tests/integrations/github-authentication.spec.ts -- --project=chromium
cd apps/web && rtk pnpm e2e:run --no-build tests/integrations/mobile-github-auth-settings.spec.ts -- --project=mobile-chrome
test -z "$(rg -l 'KANDEV_GITHUB_APP' apps docs/public || true)"
git diff --check
Also inspect desktop and mobile Playwright screenshots and verify document horizontal overflow is zero. The final security pass scans logs, API responses, redirects, executor environments, process arguments, persisted metadata, and E2E artifacts for PATs, App private keys, App client/webhook secrets, personal tokens, refresh tokens, and live installation tokens.
Risks
- Existing runtime construction assumes one swappable App. Any hidden singleton can route the right workspace through the wrong key; concurrency and negative isolation tests are mandatory.
- Imported GitHub App settings cannot all be read through GitHub APIs. The guide must separate verified identity from user-confirmed callback/webhook policy and keep capability diagnostics visible after installation.
- A manifest conversion returns the only generated private key. Persistence failure can leave an orphan App on GitHub, so recovery instructions must not claim Kandev can delete it.
- Reusing a registration is weaker isolation than separate Apps. The UI must state the shared root credential and revocation boundary before installation.
- The current runtime has no authenticated admin role. Registration catalog visibility and mutation remain acceptable only inside the documented trusted-single-user boundary.
Approval
Awaiting approval of the amended spec, ADR, wave graph, and verification commands before Task 11 starts.