fix(gateway): revoke deleted keystore-backed env vars on refresh
Force-refresh now also clears env vars that were previously injected by the keystore but no longer exist in the current injectable secret set. This lets credential deletion/revocation propagate in long-lived gateway processes without restart, while still preserving external env precedence. Adds a regression test covering deletion of a keystore-backed OPENAI_API_KEY followed by gateway refresh.
This commit is contained in:
@@ -180,6 +180,18 @@ class KeystoreClient:
|
||||
previous = dict(self._injected)
|
||||
owned = _owned_env_names()
|
||||
injected = {}
|
||||
current_names = set(secrets.keys())
|
||||
|
||||
# Force-refresh also acts as revocation for previously keystore-owned
|
||||
# env vars that have been deleted from the keystore or are no longer
|
||||
# injectable. External env vars are never in `owned`, so they are not
|
||||
# touched here.
|
||||
if force:
|
||||
removed = owned - current_names
|
||||
for name in removed:
|
||||
os.environ.pop(name, None)
|
||||
owned -= removed
|
||||
|
||||
for name, value in secrets.items():
|
||||
should_write = False
|
||||
if name not in os.environ:
|
||||
|
||||
@@ -102,3 +102,29 @@ def test_gateway_refresh_does_not_clobber_external_env(monkeypatch, tmp_path):
|
||||
ks.set_secret("OPENAI_API_KEY", "rotated-keystore-value")
|
||||
gateway_run._inject_keystore_env(force=True)
|
||||
assert os.environ.get("OPENAI_API_KEY") == "env-wins"
|
||||
|
||||
|
||||
def test_gateway_refresh_revokes_deleted_keystore_secret(monkeypatch, tmp_path):
|
||||
home = tmp_path / ".hermes"
|
||||
home.mkdir(parents=True)
|
||||
(home / ".env").write_text("")
|
||||
(home / "config.yaml").write_text("toolsets:\n- hermes-cli\n")
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(home))
|
||||
from keystore.client import KeystoreClient, reset_keystore
|
||||
reset_keystore()
|
||||
ks = KeystoreClient(home / "keystore" / "secrets.db")
|
||||
ks.initialize("passphrase")
|
||||
ks.set_secret("OPENAI_API_KEY", "sk-old")
|
||||
monkeypatch.setenv("HERMES_KEYSTORE_PASSPHRASE", "passphrase")
|
||||
monkeypatch.delenv("OPENAI_API_KEY", raising=False)
|
||||
monkeypatch.delenv("OPENROUTER_API_KEY", raising=False)
|
||||
|
||||
gateway_run = _reload_gateway_run(monkeypatch, home)
|
||||
assert os.environ.get("OPENAI_API_KEY") == "sk-old"
|
||||
|
||||
# Delete from keystore; force refresh should revoke the previously
|
||||
# injected env var from the long-lived process.
|
||||
ks.delete_secret("OPENAI_API_KEY")
|
||||
gateway_run._inject_keystore_env(force=True)
|
||||
assert os.environ.get("OPENAI_API_KEY") is None
|
||||
|
||||
Reference in New Issue
Block a user