fix: preserve persisted config environment

This commit is contained in:
Alex Schapiro
2026-08-20 16:14:11 +00:00
parent 6f88b7d7d5
commit 7a736da465
2 changed files with 61 additions and 2 deletions
+24 -2
View File
@@ -54,12 +54,16 @@ def apply_config_override(path: Path) -> None:
def persist_current() -> None:
"""Write currently-set env vars to the active config file (0o600)."""
"""Merge currently-set env vars into the active config file (0o600).
Keys already on disk are preserved (including keys unknown to this
version's schema); env vars win on conflicts.
"""
s = load_settings()
target = _override or _DEFAULT_PATH
target.parent.mkdir(parents=True, exist_ok=True)
env_block: dict[str, str] = {}
env_block: dict[str, str] = _read_persisted_env(target)
for sub_name in s.model_fields:
sub_model = getattr(s, sub_name)
if not isinstance(sub_model, BaseModel):
@@ -74,6 +78,24 @@ def persist_current() -> None:
write_secret_text(target, json.dumps({"env": env_block}, indent=2))
def _read_persisted_env(path: Path) -> dict[str, str]:
"""Read the ``{"env": {...}}`` block already stored at ``path``."""
if not path.exists():
return {}
try:
data = json.loads(path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
return {}
env_block = data.get("env", {}) if isinstance(data, dict) else {}
if not isinstance(env_block, dict):
return {}
return {
str(key).upper(): str(value)
for key, value in env_block.items()
if isinstance(value, str | int | float) and str(value)
}
def _aliases_for(finfo: FieldInfo) -> list[str]:
"""Collect every env-var name that should populate ``finfo``."""
aliases: list[str] = []
+37
View File
@@ -208,6 +208,43 @@ def test_persist_current_writes_env_block(tmp_path: Path, monkeypatch: pytest.Mo
}
def test_persist_current_preserves_keys_missing_from_env(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.delenv("STRIX_LLM", raising=False)
monkeypatch.delenv("LLM_API_KEY", raising=False)
monkeypatch.setenv("OPENAI_API_KEY", "env-key")
target = tmp_path / "cli-config.json"
target.write_text(
json.dumps({"env": {"STRIX_LLM": "file-model", "STRIX_FUTURE_KEY": "keep-me"}}),
encoding="utf-8",
)
loader.apply_config_override(target)
loader.persist_current()
assert json.loads(target.read_text(encoding="utf-8")) == {
"env": {
"STRIX_LLM": "file-model",
"STRIX_FUTURE_KEY": "keep-me",
"OPENAI_API_KEY": "env-key",
}
}
def test_persist_current_env_wins_over_persisted_value(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
monkeypatch.setenv("STRIX_LLM", "env-model")
target = tmp_path / "cli-config.json"
target.write_text(json.dumps({"env": {"STRIX_LLM": "file-model"}}), encoding="utf-8")
loader.apply_config_override(target)
loader.persist_current()
assert json.loads(target.read_text(encoding="utf-8"))["env"]["STRIX_LLM"] == "env-model"
def test_persist_current_sets_0600_mode(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv("STRIX_LLM", "persisted-model")
target = tmp_path / "cli-config.json"