Files
kandev/docs/decisions/2026-07-27-task-git-credential-policy.md
T
2026-08-02 14:13:04 +01:00

123 lines
7.5 KiB
Markdown

# ADR-2026-07-27-task-git-credential-policy: Separate GitHub Automation From Task Git Credential Policy
> Amended by
> [ADR-2026-08-02-new-workspace-github-access-defaults](2026-08-02-new-workspace-github-access-defaults.md):
> newly created workspaces persist `executor` as their initial task Git policy, while existing
> persisted and legacy fallback behavior remains unchanged.
**Status:** accepted
**Date:** 2026-07-27
**Area:** backend, frontend, security
## Context
A workspace GitHub connection currently selects both the identity used by Kandev background
automation and the credentials injected into task processes. That coupling is surprising for local
users who expect Git to use their host credential manager or SSH setup, and selecting a named
`gh` account does not mean that its host configuration should be inherited by every executor.
Managed task access also depends on a broker-aware `agentctl` and `gh` tool path; a standalone
control process can start successfully while leaving the child Git helper unable to find
`agentctl`.
## Decision
Workspace GitHub automation identity and task Git credential policy are separate workspace-owned
settings:
- `managed` is the backward-compatible fallback for existing missing or invalid settings. Kandev
injects task/repository-bound broker leases for attached GitHub
repositories. PAT, named GitHub CLI, GitHub App, and migration-only legacy connections remain
automation methods rather than task-policy values.
- `executor` is the initial mode persisted for newly created workspaces and remains an explicit
inheritance mode. Kandev injects no GitHub broker helper or `gh` shim.
Local and Worktree tasks use credentials visible on the Kandev host; Docker, SSH, Sprites, and
other remote tasks use credentials configured in that executor.
- An explicit executor-profile `GITHUB_TOKEN` or `GH_TOKEN` remains an unmanaged override. It takes
precedence when the selected policy is `managed` and is disclosed as an executor-profile token
whose actor is selected at runtime.
The policy is stored with the non-secret `github_workspace_settings` operational settings, is
copied by workspace-settings copy, and does not create another
`github_workspace_connections.source`. Missing or invalid stored values normalize to `managed` for
backward compatibility.
Managed runtime tools are installed once by the `agentctl` control process and activated only for
an instance carrying a valid broker contract. The managed tool directory contains both the
`agentctl` Git credential helper and the broker-aware `gh` shim. GitHub HTTPS helper configuration
resets the inherited helper chain before adding Kandev's helper, disables terminal prompts, and
fails closed when lease redemption or the helper fails. The contract does not claim to prevent an
arbitrary agent from manually changing a remote to SSH or invoking another credential-bearing
tool; executor isolation and agent permissions remain the boundary for that behavior.
`GIT_CONFIG_COUNT` and its indexed `GIT_CONFIG_KEY_<n>` / `GIT_CONFIG_VALUE_<n>` variables are one
ordered protocol, not independent environment variables. Every task-launch boundary that combines
environment sources must parse, compose, and contiguously reindex valid blocks. Lower-precedence
executor or host entries come first and higher-precedence task entries follow; the longest exact
suffix/prefix overlap is emitted once when a block has already been forwarded through a control
process. Kandev may reset the GitHub credential-helper chain with a later empty helper entry, but it
must preserve unrelated entries such as `core.hooksPath`, `safe.directory`, URL rewrites, and notes
configuration. Malformed indexed blocks fail task environment preparation with a credential-safe
diagnostic instead of being partially overlaid. Repository-clone subprocesses remain an explicit
exception: they intentionally build an isolated Git environment and strip ambient indexed config.
Initial launch and resume use the same policy resolver. After each successful launch or resume,
Kandev stores a versioned, non-secret `git_credential_snapshot` in task-session metadata. It
records the selected policy, effective source (`workspace`, `executor_profile`, or `executor`),
workspace method when known, known actor label or `runtime_selected`, transport, executor type,
and capture time. It never stores a token, lease, helper path, or credential-file path. The Changes
panel reads this launch-time snapshot; it does not probe the current host or executor and does not
rewrite history when workspace settings later change.
The branch disclosure shows the snapshot alongside branch/base-branch information. Fine-pointer
desktop users receive hover and keyboard-focus access; coarse-pointer users receive the same
content in a tappable drawer. GitHub settings explain every automation method in visible text and
provide a supplementary information disclosure describing how each method reaches tasks under
both policies.
Named GitHub CLI credentials remain deterministic host/login selections. Their derived bearer
tokens are cached in memory for no more than five minutes before Kandev asks the host CLI for that
exact account again; cache invalidation on connection generation changes remains immediate.
## Consequences
- Users can keep Kandev background automation on a PAT, named CLI account, or App while choosing
traditional executor Git behavior for tasks.
- Selecting GitHub CLI authentication no longer implies host credential inheritance. Managed mode
still resolves the named account on the Kandev host and brokers its bearer token to tasks.
- Existing workspaces remain managed without a migration-time behavior change.
- Host and executor Git tooling expressed through indexed environment config survives Kandev
credential injection; Kandev's later GitHub helper entries retain their intended precedence.
- The UI can truthfully identify managed actors while labeling inherited and profile-token actors
as runtime-selected instead of guessing.
- Resume may pick up a changed workspace policy or automation connection, and its new snapshot
replaces the prior launch snapshot only after the resume succeeds.
- Managed HTTPS Git and `gh` fail closed, but a local/Worktree agent still runs with host process
authority; this setting is credential routing, not a sandbox.
- Environment composition becomes fallible when an indexed Git config block is malformed, so
launch errors can identify the invalid source instead of silently producing a different Git
configuration.
## Alternatives Considered
### Treat executor inheritance as a fourth GitHub connection source
Rejected. It would conflate Kandev's background automation identity with task transport again and
would leave watches and repository discovery without a defined credential.
### Infer host inheritance from the named GitHub CLI method
Rejected. The named CLI selection is a deterministic automation identity. Remote executors cannot
inherit the Kandev host's CLI configuration, and local inference would make the same setting mean
different security policies by executor.
### Display the current workspace connection instead of a session snapshot
Rejected. Settings can change after a task starts, so current status can misrepresent the
credential contract under which the visible session actually launched.
### Probe inherited credentials to discover the actor
Rejected. Git credential managers and SSH agents may be interactive, may choose by URL at command
time, and should not be invoked merely to render UI. Unknown inherited actors are labeled
`runtime_selected`.