fix(auth): explicit-provider gate uses the credential resolver's reader
get_env_value stops at the first environ hit, so a shell that exports DEEPSEEK_API_KEY= (empty) hides a real key in .env from the gate while resolve_api_key_provider_credentials() finds it: the picker omits a provider the chat path would authenticate with. Read through get_env_value_prefer_dotenv, the same chain auth.py already uses to resolve the key, so the two can never disagree (#77007). Co-authored-by: webtecnica <webtecnica@gmail.com>
This commit is contained in:
@@ -1023,11 +1023,13 @@ def _env_secret(name: str) -> bool:
|
||||
process environ is the *launch* profile, so a DeepSeek key pasted into another
|
||||
profile's ``.env`` would be invisible to ``explicit_only`` Settings → Model
|
||||
until a Bot-chat Refresh ran against that profile's own backend.
|
||||
``get_env_value`` is the scope-aware reader (#67027): secret scope, then the
|
||||
current HERMES_HOME ``.env``.
|
||||
Same reader as the credential resolver (``get_env_value_prefer_dotenv``: the current
|
||||
HERMES_HOME ``.env`` first, then the scope-checked environ) so the gate and the key that
|
||||
actually authenticates never disagree — an empty ``DEEPSEEK_API_KEY=`` export in the parent
|
||||
shell must not hide a real key in ``.env`` (#77007).
|
||||
"""
|
||||
from hermes_cli.config import get_env_value
|
||||
return has_usable_secret(get_env_value(name) or "")
|
||||
from hermes_cli.config import get_env_value_prefer_dotenv
|
||||
return has_usable_secret(get_env_value_prefer_dotenv(name) or "")
|
||||
|
||||
|
||||
def _explicit_env_credentials_present(normalized: str) -> bool:
|
||||
|
||||
@@ -222,6 +222,22 @@ def test_profile_dotenv_key_counts_as_explicit_when_process_env_lacks_it(tmp_pat
|
||||
assert is_provider_explicitly_configured("deepseek") is False
|
||||
|
||||
|
||||
def test_dotenv_key_counts_when_shell_exports_the_var_empty(tmp_path, monkeypatch):
|
||||
"""The gate resolves through the same reader as the credential resolver
|
||||
(get_env_value_prefer_dotenv), so it agrees with the key that authenticates:
|
||||
an empty ``DEEPSEEK_API_KEY=`` inherited from the parent shell must not hide
|
||||
a real key in .env (#77007) — the resolver would use that key, so the picker
|
||||
must list the provider."""
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path / "hermes"))
|
||||
monkeypatch.setenv("DEEPSEEK_API_KEY", "")
|
||||
_write_config(tmp_path, {"model": {}})
|
||||
(tmp_path / "hermes" / ".env").write_text("DEEPSEEK_API_KEY=sk-dotenv-only-secret\n")
|
||||
|
||||
from hermes_cli.auth import is_provider_explicitly_configured, resolve_api_key_provider_credentials
|
||||
assert resolve_api_key_provider_credentials("deepseek").get("api_key") == "sk-dotenv-only-secret"
|
||||
assert is_provider_explicitly_configured("deepseek") is True
|
||||
|
||||
|
||||
# ─── aws_sdk providers (Bedrock) ─────────────────────────────────────────
|
||||
#
|
||||
# Bedrock is registered with auth_type="aws_sdk" and an empty
|
||||
|
||||
Reference in New Issue
Block a user