Skip to content

fix(model): avoid persisting key_env-resolved secrets to providers entry#16372

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-0977fdd1
Apr 27, 2026
Merged

fix(model): avoid persisting key_env-resolved secrets to providers entry#16372
teknium1 merged 1 commit into
mainfrom
hermes/hermes-0977fdd1

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Closes #15803.

Summary

hermes model no longer writes a synthesized api_key: ${KEY_ENV} to a providers: entry that only declared key_env.

Root cause: _model_flow_named_custom's providers: persistence branch always called _custom_provider_api_key_config_value(), which falls back to ${KEY_ENV} when no inline api_key exists. For the keyed schema that fallback is redundant — the runtime already resolves credentials from key_env directly — and it clutters configs that intentionally keep secrets out of config.yaml.

Changes

  • hermes_cli/main.py: gate the provider_entry["api_key"] write on whether provider_info originally carried an inline api_key (literal or ${VAR} template). Entries with only key_env stay clean.
  • tests/hermes_cli/test_custom_provider_model_switch.py: two regression tests — (a) key_env-only entry gets no api_key field after the picker, and no plaintext secret appears on disk; (b) an existing inline ${VAR} template is preserved across the picker.

Validation

E2E reproduced the reporter's exact config against unpatched main (writes api_key: ${HERMES_CRS_HENKEE_KEY}), then against the fix (entry unchanged apart from default_model update). 162 tests across 6 relevant files pass:

tests/hermes_cli/test_custom_provider_model_switch.py
tests/hermes_cli/test_user_providers_model_switch.py
tests/hermes_cli/test_terminal_menu_fallbacks.py
tests/hermes_cli/test_setup.py
tests/agent/test_auxiliary_named_custom_providers.py
tests/hermes_cli/test_runtime_provider_resolution.py

Legacy custom_providers behavior (writing ${VAR} when only key_env is set) is unchanged — still covered by the existing test_key_env_custom_provider_persists_reference_not_secret test.

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes #15803.
@teknium1 teknium1 merged commit 8258f4d into main Apr 27, 2026
11 of 12 checks passed
@teknium1 teknium1 deleted the hermes/hermes-0977fdd1 branch April 27, 2026 04:52
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P1 High — major feature broken, no workaround comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles area/auth Authentication, OAuth, credential pools labels Apr 27, 2026
negaterium pushed a commit to negaterium/hermes-agent that referenced this pull request Apr 27, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.

(cherry picked from commit 8258f4d)
cluricaun28 referenced this pull request in cluricaun28/Logos Apr 28, 2026
…try (#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes #15803.
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
dannyJ848 pushed a commit to dannyJ848/hermes-agent that referenced this pull request May 17, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
…try (NousResearch#16372)

When 'hermes model' runs against a providers: (keyed-schema) entry that
relies only on key_env, the picker resolves the env var for the live
/models request and then wrote a synthesized 'api_key: ${KEY_ENV}' back
to the providers.<key> entry. That's redundant — the runtime already
resolves from key_env directly — and it clutters configs that
intentionally keep credentials out of config.yaml.

Only persist provider_entry['api_key'] when the user originally had an
inline value (literal secret or ${VAR} template). Entries that declared
only key_env stay clean on save.

Fixes NousResearch#15803.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(model): avoid persisting key_env-resolved secrets

2 participants