Files
2026-08-24 11:09:03 +00:00

11 KiB

spec, created, status
spec created status
docs/specs/integrations/requirements/github-authentication.md 2026-08-02 completed

Implementation Plan: New Workspace GitHub Access Defaults

Overview

The confirmed root cause is that github_workspace_settings resolves a missing task policy to managed, while a new workspace has no github_workspace_connections row. Task launch therefore requests a broker lease that fails with ErrGitHubNotConfigured before the agent starts. The fix will persist executor task access for each new workspace, optionally snapshot an operator-authorized active host gh account as a named CLI connection, and leave every existing installation unchanged.

The implementation begins with failing backend and browser regressions, then adds the smallest workspace-initialization seam and GitHub persistence behavior required to make them pass. Public documentation follows after the behavior is green.


Backend

GitHub workspace default initializer

  • Add a focused workspace-default initialization path under apps/backend/internal/github/ (prefer a new workspace_defaults.go with sibling tests rather than growing service_connections.go).
  • Persist TaskGitCredentialsModeExecutor for a workspace created after this feature is active. Keep defaultWorkspaceSettings, normalizeTaskGitCredentialsMode, existing schema defaults, and upgrade fallbacks on managed; those are the backward-compatibility path for existing missing or invalid state.
  • Discover the currently active account through the service's injectable CLI account source. Only an internal caller, synthetic administrator, or real administrator may receive the host account; reuse the existing requireGHCLIOperator boundary for member denial.
  • Validate and store the exact github.com host/login as a gh_cli connection without persisting a bearer token. No active/valid CLI account is a soft condition: executor settings are still saved and workspace creation succeeds disconnected.
  • Record whether the GitHub schema belongs to a brand-new database before NewStore initializes its tables. Expose a one-shot startup method that initializes the already-seeded default workspace only in that fresh-database case. Existing databases, including workspaces with no settings row, are not backfilled or rebound.

Workspace creation seam

  • Add a narrow WorkspaceDefaultsInitializer interface and setter in apps/backend/internal/task/service/service.go.
  • Call it in CreateWorkspace after the workspace transaction succeeds and before workspace.created is published, so an immediately created task observes executor mode rather than racing an event subscriber. The initializer owns optional-CLI degradation; a returned persistence error is logged as a workspace-default initialization failure.
  • Wire the GitHub service into this seam in apps/backend/internal/backendapp/services.go after workspace authorization and connection-secret infrastructure are installed. Invoke the fresh-database bootstrap at the same composition point for the repository-seeded initial workspace.
  • Do not use a workspace.created subscription as the correctness boundary: the NATS-backed bus need not finish a subscriber before the create request can be followed by task launch.

Upgrade and security boundaries

  • Do not modify existing github_workspace_connections or github_workspace_settings.task_git_credentials_mode rows.
  • Do not change the current managed normalization for legacy missing/invalid values.
  • Do not auto-bind host gh for a non-admin member context.
  • Do not copy or persist the resolved CLI token, and do not follow later host active-account changes for an already-created workspace.

Frontend

No React component, route, API client, state slice, copy, or responsive composition changes are required. The existing Workspace GitHub access summary and connection dialog already render the backend's saved executor and gh_cli values.

Mobile parity contract

The nearest shipped mobile exemplar remains apps/web/e2e/tests/integrations/mobile-github-workspace-settings.spec.ts: the existing full-height, single-scroll-owner connection drawer and 44px task-access controls are unchanged. Update that scenario to prove the initial summary reads Inherit executor Git credentials. Because this is a persisted backend-default change with no layout, navigation, scroll, touch, or composition change, the focused existing mobile scenario satisfies mobile parity without a new mobile surface.


Tests

  • What: a new workspace always receives persisted executor task access; an internal/admin creator with a valid active CLI account also receives an exact named CLI connection. File: apps/backend/internal/github/workspace_defaults_test.go. How: SQLite-backed service tests with injectable CLI account/token validation boundaries.
  • What: member creation never receives the server operator's CLI identity; unavailable, unauthenticated, or invalid CLI discovery degrades to disconnected automation without losing executor task access. File: apps/backend/internal/github/workspace_defaults_test.go. How: table-driven service tests using real store reads and synthetic/admin/member contexts.
  • What: a database with pre-existing GitHub schema/settings is not treated as fresh and its missing or managed behavior is not rewritten, while a genuinely fresh schema initializes the seeded workspace once. Files: apps/backend/internal/github/workspace_defaults_test.go, apps/backend/internal/github/workspace_settings_test.go. How: fresh and replayed SQLite store setup with row-level assertions.
  • What: task-service workspace creation runs default initialization before publishing the created event. File: apps/backend/internal/task/service/service_resources_test.go. How: a recording initializer and event bus assert call order and error handling.
  • What: backend composition wires runtime workspace creation and fresh-install startup to the GitHub initializer. File: apps/backend/internal/backendapp/services_github_defaults_test.go (or the nearest existing service-composition test if a smaller harness is available during RED). How: real SQLite repositories with injected GitHub account resolution and stored-state assertions.
  • What: executor policy skips broker lease injection. File: apps/backend/internal/orchestrator/executor/executor_credentials_test.go. How: retain the existing executor inheritance regression as downstream contract evidence; add no duplicate test unless the new integration test cannot prove the no-lease outcome.

Targeted backend verification:

cd apps/backend && go test -tags fts5 ./internal/github ./internal/task/service ./internal/backendapp ./internal/orchestrator/executor -run 'Test.*Workspace.*Defaults|Test.*Workspace.*Initializ|TestTaskGitCredentialModeDefaultsManaged|TestApplyGitCredentialSnapshotUsesExecutorSources' -count=1

E2E Tests

  • Scenario: GIVEN a new workspace and an active mock CLI account, WHEN an administrator creates the workspace and opens Workspace GitHub access, THEN the UI shows that exact CLI automation identity and Inherit executor Git credentials. File: apps/web/e2e/tests/integrations/github-authentication.spec.ts. What to verify: automation source/login and task-access summary through the rendered settings page, with backend seeding only for the CLI-account precondition.
  • Scenario: GIVEN the initial fresh E2E workspace, WHEN desktop and mobile users open Workspace GitHub access, THEN the existing summary and dialog/drawer show executor inheritance as the initial task policy. Files: apps/web/e2e/tests/integrations/github-workspace-settings.spec.ts, apps/web/e2e/tests/integrations/mobile-github-workspace-settings.spec.ts. What to verify: desktop and mobile report the same saved policy; existing mobile geometry, scroll ownership, safe-area containment, and touch targets remain green.

Targeted browser verification after the fresh-worktree install:

cd apps && pnpm install --frozen-lockfile
cd apps && pnpm --filter @kandev/web run e2e:run -- tests/integrations/github-authentication.spec.ts tests/integrations/github-workspace-settings.spec.ts
cd apps && pnpm --filter @kandev/web run e2e:run -- --project mobile-chrome tests/integrations/mobile-github-workspace-settings.spec.ts

Public Documentation

Update docs/public/integrations.md so Inherit executor Git credentials is documented as the new-workspace default, managed credentials are described as an opt-in workspace policy, active host gh auto-binding is limited to operator-authorized creation, remote executors remain responsible for their own credentials, and upgrades are unchanged.

Validate with:

node --test scripts/validate-public-docs.test.mjs
node scripts/validate-public-docs.mjs

Verification Results

  • cd apps/backend && go test -tags fts5 ./internal/github ./internal/task/service ./internal/backendapp ./internal/orchestrator/executor -run 'Test.*Workspace.*Defaults|Test.*Workspace.*Initializ|TestTaskGitCredentialModeDefaultsManaged|TestApplyGitCredentialSnapshotUsesExecutorSources' -count=1 — 12 passed in 4 packages.
  • cd apps/backend && go test -tags fts5 ./internal/github ./internal/task/service ./internal/backendapp ./internal/orchestrator/executor -count=1 — 2402 passed in 4 packages.
  • cd apps && pnpm --filter @kandev/web run e2e:run -- tests/integrations/github-authentication.spec.ts tests/integrations/github-workspace-settings.spec.ts — 9 passed.
  • cd apps && pnpm --filter @kandev/web run e2e:run -- --project mobile-chrome tests/integrations/mobile-github-workspace-settings.spec.ts — 2 passed.
  • cd apps/backend && make lint — 0 issues.
  • cd apps && pnpm --filter @kandev/web run typecheck — passed.
  • cd apps && pnpm --filter @kandev/web run lint — passed.
  • cd apps && pnpm --filter @kandev/web run i18n:check && pnpm --filter @kandev/web run i18n:ratchet — passed.
  • node --test scripts/validate-public-docs.test.mjs — 58 passed.
  • node scripts/validate-public-docs.mjs — 41 published docs pages validated.
  • cd apps && pnpm run format:check and git diff --check — passed.

Implementation Waves And Parallel Candidates

Execution is sequential in the primary conversation; no task is marked parallel-safe because the RED tests define the contracts consumed by the backend implementation and documentation must match the final green behavior.