fix: fingerprint .env key names with the provider .env loader

This commit is contained in:
carlotestor committed 2026-09-23 15:52:14 +00:00
1 parent 7f2e812280
commit 4e17333516
2 files changed
+23 -18

No files matched your search

+5 -18
View File
@@ -7918,28 +7918,15 @@ def _models_cache_env_fingerprint(path: Path) -> dict:
Credential presence decides which providers are detected; values are
never recorded, so rotating a key keeps the snapshot.
"""
# Same parser provider detection uses, so the key names match exactly.
from api.providers import _load_env_file
p = Path(path).expanduser()
fp: dict = {"path": str(p)}
try:
text = p.read_text(encoding="utf-8")
except FileNotFoundError:
if not p.exists():
fp["missing"] = True
return fp
except OSError:
st = p.stat()
fp["mtime_ns"], fp["size"] = st.st_mtime_ns, st.st_size
return fp
keys = set()
for line in text.splitlines():
line = line.strip()
if line.startswith("export "):
line = line[len("export "):].lstrip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
if v.strip().strip('"').strip("'"):
keys.add(k.strip())
fp["present_keys"] = sorted(keys)
fp["present_keys"] = sorted(k for k, v in _load_env_file(p).items() if v)
return fp
@@ -118,6 +118,24 @@ def test_switch_after_removing_env_key_rejects_snapshot(two_profiles):
assert _switch_to_demo_and_fetch(two_profiles)["default_model"] == "fresh-model"
def test_switch_after_export_prefix_rejects_snapshot(two_profiles):
"""`export KEY=` is key `export KEY` to the profile .env loaders, so the provider key is gone."""
env_file = two_profiles.demo_home / ".env"
env_file.write_text("DEEPSEEK_API_KEY=sk-old\n", encoding="utf-8")
_save_demo_snapshot(two_profiles)
env_file.write_text("export DEEPSEEK_API_KEY=sk-old\n", encoding="utf-8")
assert _switch_to_demo_and_fetch(two_profiles)["default_model"] == "fresh-model"
def test_env_fingerprint_keys_match_provider_env_loader(two_profiles):
from api.providers import _load_env_file
env_file = two_profiles.demo_home / ".env"
env_file.write_text("export A=1\nB='x'\nC=\n# D=1\n", encoding="utf-8")
loaded = sorted(k for k, v in _load_env_file(env_file).items() if v)
assert two_profiles.cfg._models_cache_env_fingerprint(env_file)["present_keys"] == loaded
def test_env_value_rotation_keeps_snapshot_and_fingerprint_has_no_secret(two_profiles):
env_file = two_profiles.demo_home / ".env"
env_file.write_text("DEEPSEEK_API_KEY=sk-secret-one\n", encoding="utf-8")