Skip to content

fix(settings): API key export overwrites env; drop multi-tenant docs claim#109

Open
shoom1 wants to merge 1 commit into
developfrom
fix/api-key-export
Open

fix(settings): API key export overwrites env; drop multi-tenant docs claim#109
shoom1 wants to merge 1 commit into
developfrom
fix/api-key-export

Conversation

@shoom1

@shoom1 shoom1 commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Review finding 7, countered

Confirmed mechanics: initialize_services() exports keys to env with a set-if-absent guard, so the first exporting manager silently pinned credentials for every later settings instance in the process — while config.py advertised SettingsContext for "multi-tenant" use.

The reviewer's prescription — pass credentials directly to every provider client — fights ADK 1.x: AnthropicLlm/Gemini construct their SDK clients from env vars internally (our code comments on that reliance), and the LangChain clients that do accept api_key= belong to the backend slated for retirement. Injecting keys would mean subclassing ADK's LLM classes for a multi-tenant scenario this single-user CLI framework doesn't have.

Change

  • export_api_keys_to_env() now overwrites env from the settings instance. Precedence-consistent: the key fields bind only via their env alias (validation_alias, no populate_by_name — constructor kwargs and settings.json never populate them, verified empirically), so settings and env diverge only when the process env changed after this instance loaded — e.g. an earlier manager's export, or a class-specific env_file. In both cases this instance's configured value must win. Unset keys still leave external env vars untouched.
  • config.py module docs: SettingsContext is for isolated settings lookup (tests, per-request overrides); explicitly documents that credentials become process-global env vars at manager init.

Discovered while verifying (not addressed here)

validation_alias without populate_by_name means BaseSettings(anthropic_api_key=...) kwargs and ~/.{app}/settings.json keys silently never bind — only the aliased env var or a .env file does. Several tests/fixtures pass such kwargs believing they work. Fixing that (e.g. AliasChoices(alias, field_name) or populate_by_name=True) intersects the P0-1 trust filters and deserves its own reviewed change.

Tests

TDD: overwrite test watched fail against the old guard via stash A/B (env mutated after load → old code kept the stale key), plus a pin that unset keys never clobber external env. Full offline suite: 1983 passed.

https://claude.ai/code/session_01SwkKXQpy3JLEqrPkQA8QRv

…claim

Review finding 7 (countered): export_api_keys_to_env() set provider env
vars only when absent, so in a process with two settings instances the
first manager's export silently pinned credentials for every later one —
while config.py advertised SettingsContext for multi-tenant use.

The reviewer's fix (pass credentials to every provider client) fights
ADK 1.x: AnthropicLlm/Gemini construct SDK clients from env internally.
Instead:
- export now OVERWRITES env from the settings instance. This is
  precedence-consistent: the key fields bind only via their env alias
  (validation_alias, no populate_by_name — constructor kwargs and JSON
  files never set them), so divergence only means the process env changed
  after this instance loaded, and the configured value must win. Unset
  keys still leave the environment untouched.
- config.py no longer claims multi-tenant isolation for SettingsContext;
  it documents that credentials are process-global env vars.

Claude-Session: https://claude.ai/code/session_01SwkKXQpy3JLEqrPkQA8QRv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant