fix(docker): gate gh/az seeding on its switch; no shared git sign-in for non-admin clones

Addresses the review on #472.

- CRED_STORES: `.config/gh` and `.azure` now carry `enabledByEnv`
  (CODEMAN_AGENT_IMAGE_INSTALL_GH / _AZ), and resolveDockerCredentialArtifacts
  skips a store unless that variable is exactly `1`, read at container
  create. A host that merely has ~/.config/gh/hosts.yml or a plaintext MSAL
  cache no longer copies them into every case container. Tests: the default
  environment seeds neither even with the files present, and each store
  follows only its own switch.
- Multi-user mode: a non-admin's Clone Repo clone and preflight run with
  `git -c credential.helper=` (GIT_NO_CREDENTIAL_HELPERS, placed before the
  subcommand), so the server account's helpers are never lent to them.
  Verified against a real private repo that it also clears the URL-scoped
  credential.<url>.helper entries, and that public clones still work.
  Tests: the argv in test/git-clone.test.ts, and the route decision
  (non-admin cleared; admin and single-user kept) in
  test/routes/case-clone-credential-helpers.test.ts.
- Docs: recreate the case container to pick up seeds (docker/README.md,
  Docker-Cases wiki, docker-cases.md); the multi-user behaviour in
  docker/README.md and security-architecture.md; "functionally unchanged"
  instead of "unchanged" for an image built with both switches off
  (server.Dockerfile comment, README, changeset).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0167CiuzLrmjYWxwKp3rMWjw
This commit is contained in:
Devvyn
2026-09-23 14:44:26 +08:00
co-authored by Claude Opus 5.5
parent 5cf5a45438
commit 02e40f506b
13 changed files with 250 additions and 35 deletions
+10 -7
View File
@@ -120,17 +120,20 @@ Codeman reads it host-side for history and resume.
**Git hosts.** The agent image can also include the GitHub CLI (`gh`) and the Azure CLI (`az`,
with the `azure-devops` extension), off by default, and its git then uses them as credential
helpers for github.com and Azure DevOps. Their sign-ins are seeded like everything else, file by file:
`~/.config/gh/hosts.yml` and `config.yml`, and the sign-in files from `~/.azure` (not its
logs or extensions). So once `gh auth login` / `az login` have been run where Codeman runs,
agents in a Docker case can clone and push private repos on those hosts. Two limits:
helpers for github.com and Azure DevOps. When the matching switch is on, their sign-ins are
seeded like everything else, file by file: `~/.config/gh/hosts.yml` and `config.yml`, and the
sign-in files from `~/.azure` (not its logs or extensions). With a switch off they are never
copied in, even if the files exist. So once a switch is on and `gh auth login` / `az login`
have been run where Codeman runs, agents in a Docker case can clone and push private repos on
those hosts. Two limits:
- A token held in a desktop keyring or an encrypted token cache (Windows, macOS) is not
inside those files and does not carry in. Sign in inside the container instead. The Docker
server image and a headless Linux host keep it in the files, so they carry.
- The copy happens only when the file is not already in the container, so a sign-in made
after a case container was created reaches that container only once it is recreated
(or once you sign in inside it).
- The sign-ins are mounted when a case container is **created**, so an existing container
never picks them up. After turning a switch on, signing in, or rebuilding the agent image,
**recreate the case container**: remove it, and the next session in that case creates a
fresh one. (Or sign in inside the existing container instead.)
This hands a GitHub token and an Azure sign-in to every agent in a seeded Docker case, the
same trust you already give it with Claude, Codex or gcloud. Turn seeding off for a case that