17 KiB
spec, created, status
| spec | created | status |
|---|---|---|
| docs/specs/integrations/github-authentication.md | 2026-07-27 | complete |
Implementation Plan: Task Git Credential Policy And Identity
Overview
Fix the confirmed standalone managed-helper wiring failure while separating workspace GitHub automation from task Git credential routing. Persist the policy first, then make initial launch and resume resolve the same effective contract and record a truthful session snapshot. Finish with self-documenting settings, responsive Changes-panel identity disclosure, focused E2E coverage, and public documentation.
Confirmed root causes:
- The standalone launcher resolves and starts the
agentctlcontrol binary by absolute path, but the per-task Git config stores!agentctl git-credential. The control process only creates/prepends itsghshim directory when broker environment exists at control-process startup; standalone broker data arrives later in the per-instance environment. Therefore child Git cannot findagentctl. - Task environments currently merge
GIT_CONFIG_COUNTand indexed keys as ordinary map entries. A Kandev block with count 2 overwrites a host/executor block's count and first two entries, so unrelated tools such as hooks and Git notes disappear. The same defect can hide Docker'ssafe.directoryand URL rewrites. A focused reproduction againstCollectAgentEnvproduced count 2 where the correct composed result is count 4. - Resume currently does not rebuild the broker contract at all.
Backend
Ordered indexed Git configuration
- Add a shared backend utility for parsing, validating, composing, and contiguously serializing the
GIT_CONFIG_COUNT/GIT_CONFIG_KEY_<n>/GIT_CONFIG_VALUE_<n>protocol. - Composition preserves source order, appends higher-precedence entries, and removes only the longest exact suffix/prefix overlap when the same block has already passed through a control process. It never deduplicates arbitrary repeated Git keys because repeated keys can be meaningful.
- Use structured composition in agent-profile/request merges, route overrides, container environment construction, remote forwarding, and agentctl's parent-plus-instance collection. Ordinary scalar environment variables retain their documented precedence.
- Keep
internal/repocloneisolated: managed clone subprocesses intentionally strip ambient Git configuration and build a closed credential environment. - Add a real Git subprocess regression that starts with locstat-shaped
core.hooksPathandnotes.augment.mergeStrategyentries, adds Kandev's helper entries, makes a commit, and verifies the hook ran. Add focused standalone, Docker, SSH/remote, overlap, precedence, malformed-block, and bounded-count tests.
Workspace policy persistence and description
- In
apps/backend/internal/github/models.go, addTaskGitCredentialsModeManaged,TaskGitCredentialsModeExecutor, andWorkspaceSettings.TaskGitCredentialsMode/UpdateWorkspaceSettingsRequest.TaskGitCredentialsMode. - In
apps/backend/internal/github/store.go, addgithub_workspace_settings.task_git_credentials_mode TEXT NOT NULL DEFAULT 'managed'to fresh schema and a fail-loud, idempotent startup migration. Include it in defaults, normalization, reads, upserts, partial patches, and workspace-settings copy. - In
apps/backend/internal/github/workspace_settings_service.go, reject unknown policy values without mutating the row. - Add a non-secret service description that combines the policy with
github_workspace_connectionsand, for Apps, registration display identity. It returns the selected mode, method, and known actor context without resolving or exposing a credential. - Extend the existing
/api/v1/github/workspace-settingsresponse/update contract. Authorization remains the existing workspace-settings authorization path.
Launch/resume resolution and session snapshot
- In
apps/backend/internal/task/models/models.go, addSessionMetaKeyGitCredentialSnapshot, a versionedGitCredentialSnapshottype, and a JSON-rehydration-safe loader. - In
apps/backend/internal/orchestrator/executor/executor.goandexecutor_credentials.go, add a task Git credential policy resolver wired besideGitHubCredentialLeaseIssuer. Resolve one of:workspace,executor_profile, orexecutor. - Move effective GitHub credential configuration out of the middle of
buildLaunchAgentRequestso it runs after profile/request environment is final. Reuse the same function frombuildResumeRequestafterresolveAllRepoInfo. - For managed workspace credentials, clear stale broker keys, reset the GitHub HTTPS helper chain
with an empty helper before Kandev's helper, set
credential.useHttpPath=true, and disable terminal prompts. Executor inheritance removes/omits Kandev broker/helper/shim configuration. - Put the candidate snapshot on the in-memory session before lifecycle launch, but persist it only
through the existing successful
persistLaunchState/persistResumeStatefull-row write. A failed operation leaves the prior durable snapshot unchanged. - In
apps/backend/internal/backendapp/orchestrator.go, adapt the GitHub service's non-secret policy descriptor into the executor interface alongside the existing lease adapter.
Managed runtime tools and CLI refresh
- Refactor
apps/backend/cmd/agentctl/github_cli_shim.goso the control process always creates one private managed GitHub tool directory containing bothghandagentctllinks/copies, records its path, and does not globally prepend it for every instance. - In
apps/backend/internal/agentctl/server/config/config.go, prepend that directory only when the instance's additional environment contains the complete broker contract. All agent processes, shells, background commands, and agentctl Git operations then share the same per-instance PATH. - Preserve
runGitHubCLIShimlookup of the realghoutside the managed directory. Executor inheritance and profile-token override instances must see the normal executor PATH. - Add a real subprocess regression around the standalone shape: control
agentctlstarts without broker env, a broker-enabled instance receives it later, and bothgit credential fillandghresolve through the managed tools. Missing broker/helper fails instead of consulting an ambient helper. - In
apps/backend/internal/github/auth_resolver.go, give named-CLI cached credentials a separate five-minute cache deadline without pretending the provider token itself has an expiry. Generation invalidation remains immediate.
Frontend
Unified GitHub access configuration
- Extend
GitHubWorkspaceSettingsandUpdateGitHubWorkspaceSettingsRequestinapps/web/lib/types/github.ts. - Refactor
apps/web/components/github/github-task-credentials-section.tsxfrom a standalone settings section into reusable task-access summary and dialog controls with two explicit choices: Managed workspace credentials and Inherit executor Git credentials. The dialog owns the draft, failure feedback, and saved baseline. - Visible copy must explain local/Worktree host behavior, remote executor behavior, profile-token
precedence, and when each choice applies. Supplementary responsive help explains the injected
agentctlGit credential helper, scoped broker lease, broker-awareghshim, and launch/resume timing without exposing credentials. - Update
github-auth-method-list.tsx,github-connection-dialog.tsx, andgithub-settings.tsxso PAT, named CLI, and App cards state where their credential is stored/resolved and how managed tasks receive it; the task policy controls live below the method controls in the same bounded dialog/drawer. Remove the standalone Task Git credentials section from the settings page. - Replace the PAT, CLI, and task-policy submission buttons with one dialog-level Save changes action in a fixed bottom row that persists every changed local draft. Keep one scrolling content region above it, add a bottom fade as an overflow cue, place the GitHub CLI card first, and use compact spacing between task-access options. App create/import/install remain workflow actions because they navigate through GitHub instead of saving a local credential draft.
- Update
github-status.tsxso the Workspace GitHub access summary shows the current task access mode beside the automation identity and refreshes after a successful dialog submission. - Desktop retains a bounded but wider dialog. Mobile retains the existing full-height Drawer, one internal scroll owner, a safe-area-aware fixed footer, 44px controls, and no horizontal overflow.
Changes branch credential disclosure
- Add a pure parser/view-model module beside the Changes panel that reads
git_credential_snapshotfrom the activeTaskSession.metadata, tolerates malformed/legacy values, and produces display labels without guessing unknown actors. - Extract the current branch-card body from
apps/web/components/task/changes-panel-header.tsx. Keep the compact fine-pointer trigger, but make it keyboard-focus accessible and include policy, effective method/source, actor, and transport below the existing branch/base-branch rows. - Use
useTouchDrawerfor coarse pointers. The mobile trigger is at least 44px and opens a Drawer containing the same branch editing/base-branch controls and credential truth; desktop keeps the hover/focus card. - Select the active session snapshot in
useChangesPanelDataand pass the normalized disclosure through both desktopchanges-panel.tsxandmobile/mobile-changes-panel.tsx.
Tests
- What: fresh/replayed schemas default existing and new workspaces to
managed; policy round-trips, partial updates reject invalid values, and settings copy includes policy but not authentication.
File:apps/backend/internal/github/workspace_settings_test.go,copy_test.go, and focused migration tests.
How: real SQLite store/service tests, including same-database schema replay. - What: the internal policy description identifies PAT/CLI humans and App registration context
without resolving tokens, while executor actors remain unknown.
File: focused tests underapps/backend/internal/github/.
How: table-driven service tests with fake connections/registration store. - What: initial launch and resume produce the same managed/executor/profile-override contract;
managed helper chains reset, inheritance injects nothing, and only successful lifecycle launches
persist a new session snapshot.
File:apps/backend/internal/orchestrator/executor/executor_credentials_test.go,executor_resume_test.go, and launch-path tests.
How: table-driven unit tests plus mocked lifecycle success/failure integration tests. - What: host/executor/profile/task indexed Git config blocks compose in precedence order,
already-forwarded suffixes occur once, malformed blocks fail clearly, and unrelated settings
remain active beside Kandev's managed helper.
File: new shared utility tests,apps/backend/internal/agentctl/server/config/config_test.go,apps/backend/internal/agent/runtime/lifecycle/executor_docker_test.go, and focused remote tests.
How: table-driven block composition plus a temp-repository real Git commit/hook subprocess regression using locstat-shaped entries. - What: standalone per-instance broker activation makes
agentctlandghdiscoverable even though the control process started without broker env; inherit/override instances do not activate the tool directory.
File:apps/backend/cmd/agentctl/github_cli_shim_test.go,apps/backend/internal/agentctl/server/config/config_test.go.
How: temp executable/subprocess and fake HTTP broker tests; invoke real Git credential plumbing where supported. - What: named CLI cache entries re-resolve after five minutes and still invalidate immediately
on generation changes.
File:apps/backend/internal/github/auth_resolver_test.go.
How: deterministic fake clock and call counter. - What: settings drafts load, save, discard, and explain both policies and every automation
method.
File:
apps/web/components/github/github-connection-dialog.test.tsxand focused tests besideapps/web/components/github/github-task-credentials-section.tsxif state is extracted. How: mocked workspace-settings API promises; verify compact summary, explicit dialog save, close/discard behavior, refresh, and failure retention. - What: valid/malformed/missing session snapshots produce truthful disclosure labels, never an
inferred actor.
File: new Changes credential view-model test and focused header component test.
How: table-driven Vitest plus keyboard-focus component test underTooltipProvider.
Targeted pre-PR commands are recorded in the task files.
E2E Tests
- Scenario: GIVEN workspace settings, WHEN the user sees the compact Task access summary, opens
Change GitHub connection, switches to executor inheritance, and explicitly saves, THEN the API
persists
executor, the summary updates, reopening retains the saved mode, and the automation identity remains unchanged. File: extendapps/web/e2e/tests/integrations/github-workspace-settings.spec.ts. - Scenario: GIVEN a coarse-pointer settings viewport, WHEN Change GitHub connection opens, THEN
its full-height Drawer contains the task access controls in the same single scroll body, the
controls meet 44px targets, saving updates the page summary, and neither surface has horizontal
overflow.
File: extend
apps/web/e2e/tests/integrations/mobile-github-workspace-settings.spec.ts. - Scenario: GIVEN a session seeded with a managed CLI or App snapshot, WHEN a desktop user
hovers/focuses the Changes branch trigger, THEN branch/base information and launch-time actor,
method, and managed transport are visible.
File:apps/web/e2e/tests/git/git-credential-identity.spec.ts. - Scenario: GIVEN an inherited or profile-token snapshot on a coarse-pointer task view, WHEN the
branch trigger is tapped, THEN a Drawer labels the actor runtime-selected, has a 44px trigger, and
does not overflow.
File:apps/web/e2e/tests/git/mobile-git-credential-identity.spec.ts.
Production E2E runs only after rebuilding backend and Vite artifacts.
Public Documentation
- Update
docs/public/integrations.md,docs/public/executors.md, anddocs/public/use-kandev.mdto separate workspace automation method from task credential policy, describe named CLI brokerage, explain executor inheritance, and document the Changes snapshot. - Update
docs/public/integrations.mdso users find task access inside Change GitHub connection and understand the compact Workspace GitHub access summary; do not describe a standalone Task Git credentials section. - Update troubleshooting so
agentctl: command not foundis a managed-runtime defect rather than a prompt to fall back to personal SSH, and distinguish managed-helper failure from missing executor credentials.
Implementation Waves And Parallel Candidates
Wave 1:
Wave 2 (parallel candidates — user authorization required):
Wave 3 (parallel candidates — user authorization required):
Wave 4:
Wave 5:
The default execution is sequential in this primary conversation. Waves identify dependency-safe opportunities only and do not authorize subagents.
Risks
- Local and Worktree agents retain host process authority. Managed routing can fail closed for
Kandev-injected GitHub HTTPS/
gh, but cannot prevent a capable agent from selecting SSH or another host tool. - The helper-reset entry must be ordered before Kandev's helper without deleting unrelated caller-supplied Git config.
- Indexed Git config keys form one structured protocol. Plain map overlay at any launch boundary can regress host tooling; arbitrary de-duplication can also change the meaning of multi-valued Git settings.
- Docker and remote control processes can already contain the task suffix before it is forwarded to an instance, so composition must remove only an exact boundary overlap.
- Resume must resolve every attached repository, not only the legacy primary fields.
- The snapshot is launch-time truth. Rendering current workspace status in its place would reintroduce misleading identity.
- Agentctl tool-directory activation must be per instance so executor inheritance and explicit profile-token overrides do not accidentally invoke the broker shim.
- Workspace connection and task policy remain separate persistence operations inside one dialog. The single submission must report complete success only when every changed operation succeeds, refresh any partial success, and preserve failed or unsaved drafts for retry.