diff --git a/hermes_cli/env_loader.py b/hermes_cli/env_loader.py index ce64064b56..6cb02dfe99 100644 --- a/hermes_cli/env_loader.py +++ b/hermes_cli/env_loader.py @@ -142,8 +142,7 @@ def _hydrate_profile_secret_sources(home: Path) -> dict[str, str]: continue _SECRET_SOURCES[name] = applied.source values[name] = value - if values: - _SECRET_SOURCE_VALUES_BY_HOME[home_key] = values + _SECRET_SOURCE_VALUES_BY_HOME[home_key] = values return dict(values) diff --git a/tests/agent/test_env_loader_secret_sources.py b/tests/agent/test_env_loader_secret_sources.py index 4fc47bc115..b21ed48e53 100644 --- a/tests/agent/test_env_loader_secret_sources.py +++ b/tests/agent/test_env_loader_secret_sources.py @@ -377,6 +377,64 @@ def test_cold_profile_hydration_retries_failed_source(tmp_path, monkeypatch): assert attempts == 2 +def test_cold_profile_hydration_replaces_partial_snapshot_after_failed_retry( + tmp_path, monkeypatch +): + """Each retry replaces the prior profile snapshot, including with an empty result.""" + from agent.secret_sources.base import ErrorKind, FetchResult + from agent.secret_sources.registry import AppliedVar, ApplyReport, SourceReport + from agent.secret_sources import registry as reg_module + + (tmp_path / "config.yaml").write_text( + "secrets:\n command:\n enabled: true\n", encoding="utf-8" + ) + attempts = 0 + + def _apply_with_stale_partial_value(_cfg, _home_path, environ=None): + nonlocal attempts + attempts += 1 + failed = FetchResult().fail("helper exited 1", ErrorKind.AUTH_FAILED) + if attempts == 1: + environ["OPENAI_API_KEY"] = "first-value" + return ApplyReport( + sources=[ + SourceReport( + name="onepassword", + label="1Password", + result=FetchResult(secrets={"OPENAI_API_KEY": "first-value"}), + applied=["OPENAI_API_KEY"], + ), + SourceReport(name="command", label="command", result=failed), + ], + provenance={ + "OPENAI_API_KEY": AppliedVar( + name="OPENAI_API_KEY", + source="onepassword", + shape="bulk", + overrode_env=False, + ) + }, + ) + return ApplyReport( + sources=[ + SourceReport(name="onepassword", label="1Password", result=failed), + SourceReport(name="command", label="command", result=failed), + ] + ) + + monkeypatch.setattr(reg_module, "apply_all", _apply_with_stale_partial_value) + + assert env_loader.hydrate_profile_secret_sources(tmp_path) == { + "OPENAI_API_KEY": "first-value" + } + assert env_loader.get_secret_source_values(tmp_path) == { + "OPENAI_API_KEY": "first-value" + } + assert env_loader.hydrate_profile_secret_sources(tmp_path) == {} + assert env_loader.get_secret_source_values(tmp_path) == {} + assert attempts == 2 + + def test_apply_external_secret_sources_noop_when_disabled(tmp_path, monkeypatch): """Disabled Bitwarden config must not touch the source map."""