11 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/integrations/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 newworkspace_defaults.gowith sibling tests rather than growingservice_connections.go). - Persist
TaskGitCredentialsModeExecutorfor a workspace created after this feature is active. KeepdefaultWorkspaceSettings,normalizeTaskGitCredentialsMode, existing schema defaults, and upgrade fallbacks onmanaged; 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
requireGHCLIOperatorboundary for member denial. - Validate and store the exact
github.comhost/login as agh_cliconnection 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
NewStoreinitializes 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
WorkspaceDefaultsInitializerinterface and setter inapps/backend/internal/task/service/service.go. - Call it in
CreateWorkspaceafter the workspace transaction succeeds and beforeworkspace.createdis 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.goafter 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.createdsubscription 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_connectionsorgithub_workspace_settings.task_git_credentials_moderows. - Do not change the current
managednormalization for legacy missing/invalid values. - Do not auto-bind host
ghfor 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 existingexecutor inheritanceregression 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:checkandgit 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.