Skip to content

feat: read DOCKER_AGENT_ENV_-prefixed secret variables - #4708

Merged
dgageot merged 4 commits into
mainfrom
feat/docker-agent-env-prefix
Oct 23, 2026
Merged

dgageot merged 4 commits into
mainfrom
feat/docker-agent-env-prefix

Conversation

@aheritier

@aheritier aheritier commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #4702

Summary

docker-agent shares variable names with other tools: Claude Code reads ANTHROPIC_API_KEY, Codex reads OPENAI_API_KEY. Exporting ANTHROPIC_API_KEY="op://…" to benefit from 1Password references breaks those tools, which do not resolve op://.

docker-agent now looks up DOCKER_AGENT_ENV_<NAME> before <NAME>:

export ANTHROPIC_API_KEY=sk-ant-...                                         # other tools
export DOCKER_AGENT_ENV_ANTHROPIC_API_KEY="op://Personal/Anthropic/api-key" # docker-agent

Changes

  • pkg/environment: PrefixedProvider and LookupNames; a single NewChain constructor (OnePassword(Prefixed(Multi(...)))) used by NewDefaultProvider and by --env-from-file in pkg/config/runtime.go.
  • docker agent doctor: its lookup env honours the override (auto-selection, agent-file checks), findSource mirrors the run-time order, and the name found is reported as a new optional found_as JSON field; env_var stays the canonical name.
  • Secrets guide: "Docker Agent-only variables" subsection.

Behavior decisions

  1. Prefix DOCKER_AGENT_ENV_, not DOCKER_AGENT_. DOCKER_AGENT_ is docker-agent's settings namespace (DOCKER_AGENT_REMOTE_AUTH_TOKEN, DOCKER_AGENT_ENCRYPT_KEY, DOCKER_AGENT_DATA_DIR, …). With a bare DOCKER_AGENT_ prefix, an MCP ${REMOTE_AUTH_TOKEN} would resolve to docker-agent's own token. Names already in DOCKER_AGENT_ are never looked up as overrides.
  2. Precedence: the override wins across the whole chain, --env-from-file included.
  3. Empty override falls back to <NAME>, so a blank line or export X= cannot hide a valid key. Doctor and the runtime agree on this.

Side effect: op:// values in --env-from-file were not resolved before (env files sat outside the 1Password wrapper, although the docs said they were); they are now.

Out of scope

  • The TUI transcriber reads OPENAI_API_KEY with os.Getenv, bypassing the chain. Fixing it needs lazy resolution in pkg/audio/transcribe to avoid an op prompt on every TUI launch; follow-up PR. Documented.
  • Keys injected by the --sandbox proxy are not read through the chain; documented.

Tests

  • PrefixedProvider table test asserting value and names looked up, including the settings-namespace case that would have leaked.
  • NewDefaultProvider and RuntimeConfig.EnvProvider: overrides span the default chain and --env-from-file in both directions.
  • doctor: auto-selection with only the override set and DMR down (mutation-checked), JSON env_var/found_as, agent-file requirements, findSource precedence and empty-override fallback.

References

Topic Link
Feature issue #4702
Default secret chain pkg/environment/default.go
--env-from-file chain pkg/config/runtime.go (computedEnvProvider)
1Password resolution pkg/environment/onepassword.go, 1Password CLI op read
Sandbox env forwarding pkg/sandbox/sandbox.go (EnvForSource, proxyManagedEnvVars)
Secrets guide docs/guides/secrets/index.md
Related #4701 (docs), #4703 (credential helper for all secrets)

This is part 1 of 2 in a stack made with GitButler:

@aheritier
aheritier requested a review from a team as a code owner October 22, 2026 18:37
Copilot AI balanced review requested due to automatic review settings October 22, 2026 18:37
@aheritier
aheritier enabled stacked auto-merge October 22, 2026 18:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Doctor can report an available credential that runtime ignores when a higher-priority source contains an empty override.

1 open issue
What changed in this PR

Adds Docker Agent-specific secret overrides so users can keep separate credentials or 1Password references without affecting other tools that share the standard environment variable names.

Changes:

  • Introduces DOCKER_AGENT_ENV_ lookup precedence across default sources and --env-from-file.
  • Updates doctor to recognize overrides and report their names through found_as.
  • Adds precedence tests and documents usage, empty-value fallback, and limitations.
File Description
pkg/​environment/​prefixed.go Adds override lookup with settings-namespace protection.
pkg/​environment/​prefixed_test.go Tests precedence, fallback, and namespace isolation.
pkg/​environment/​default.go Centralizes override and 1Password provider composition.
pkg/​environment/​default_test.go Tests override precedence across default sources.
pkg/​config/​runtime.go Includes explicit env files in the shared secret chain.
pkg/​config/​runtime_test.go Tests precedence between env files and default sources.
docs/​guides/​secrets/​index.md Documents overrides and transcription/sandbox limitations.
cmd/​root/​doctor.go Recognizes overrides and reports credential source names.
cmd/​root/​doctor_test.go Tests doctor selection, reporting, and override lookup.

Review effort: Balanced

Comment thread cmd/root/doctor.go
Comment on lines +542 to +544
if value, ok := s.Provider.Get(ctx, candidate); ok && value != "" {
return s.Name, candidate, true
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, fixed in fff6189, but on the runtime side rather than in doctor: the docs say an empty override is ignored, so the empty shell value should not hide the env-file override. PrefixedProvider now takes the sources and skips empty overrides source by source, which is what findSource already did. --env-from-file goes through the same NewChain, so it is covered too.

Regression tests: TestPrefixedProvider_EmptyOverrideDoesNotHideLaterSources (runtime) and TestFindSource_EmptyOverrideDoesNotHideLaterOverride, which also asserts doctor and the run-time chain agree.

@aheritier
aheritier force-pushed the feat/docker-agent-env-prefix branch from 2cc8ba1 to fff6189 Compare October 22, 2026 18:53
@aheritier aheritier added area/cli CLI commands, flags, output formatting area/config For configuration parsing, YAML, environment variables area/docs Documentation changes kind/feat PR adds a new feature (maps to feat:). Use on PRs only. status/needs-signed-commits Some commits in the PR are signed with a valid SSH/GPG key labels Oct 22, 2026
@aheritier

Copy link
Copy Markdown
Collaborator Author

👋 Some commits in this PR are not signed and verified by GitHub. Please sign your commits with a GPG or SSH key registered in your GitHub account, then force-push.\n\nCommits that are not verified: 5283a4f, 3804510, a23c44e\n\nSee GitHub\x27s guide on signing commits for setup instructions. I\x27ve added status/needs-signed-commits; it will be removed automatically once every commit in this PR carries a valid GitHub-verified signature.

DOCKER_AGENT_ENV_<NAME> now shadows <NAME>, so docker-agent can get its own
value (e.g. an op:// reference) for variables that other tools such as
Claude Code and Codex also read.

- One chain constructor, NewChain, serves the default chain and
  --env-from-file, so the override spans every source; op:// values in
  --env-from-file are now resolved as well.
- An empty override falls back to <NAME>.
- The prefix is a sub-namespace of DOCKER_AGENT_ and settings in that
  namespace are never looked up as overrides, so  can
  never resolve to DOCKER_AGENT_REMOTE_AUTH_TOKEN.

Refs #4702

Signed-off-by: Arnaud Héritier <aheritier@apache.org>.
Doctor's lookup env honours the override, so auto-selection and agent-file
checks match the provider table. findSource checks the override across all
sources first, mirroring the run-time chain. env_var stays the canonical
name; the override name is reported as found_as.

Refs #4702

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
Refs #4702

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
…sources

PrefixedProvider read overrides through a MultiProvider, which stops at
the first source that defines the variable, even when empty. An empty
shell DOCKER_AGENT_ENV_X therefore hid a DOCKER_AGENT_ENV_X in the
docker-agent env file, while doctor reported the latter as found.
PrefixedProvider now takes the sources and skips empty overrides source
by source, matching doctor and the documented behavior.

Signed-off-by: Arnaud Héritier <aheritier@apache.org>
@aheritier
aheritier force-pushed the feat/docker-agent-env-prefix branch from fff6189 to f630e5b Compare October 22, 2026 19:03
@aheritier
aheritier disabled stacked auto-merge October 22, 2026 19:28
@aheritier
aheritier added this pull request to stack #4711 October 22, 2026 19:29
@aheritier
aheritier enabled stacked auto-merge October 22, 2026 19:29
@aheritier
aheritier added this pull request to the merge queue Oct 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 23, 2026
@aheritier aheritier removed the status/needs-signed-commits Some commits in the PR are signed with a valid SSH/GPG key label Oct 23, 2026
@dgageot
dgageot added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 2fe0460 Oct 23, 2026
22 checks passed
@dgageot
dgageot deleted the feat/docker-agent-env-prefix branch October 23, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli CLI commands, flags, output formatting area/config For configuration parsing, YAML, environment variables area/docs Documentation changes kind/feat PR adds a new feature (maps to feat:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Read DOCKER_AGENT_ENV_-prefixed secret variables before the plain names

4 participants