mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-21 00:21:49 +00:00
fix(vault): key the secret cache by url and data field
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
15bfe8f28a
commit
4694bd0c63
2 changed files with 21 additions and 7 deletions
|
|
@ -39,6 +39,7 @@ class _VaultSecretTarget(TypedDict):
|
|||
url: ReadOnly[str]
|
||||
data_key: ReadOnly[str]
|
||||
secret_name: ReadOnly[str]
|
||||
cache_key: ReadOnly[str]
|
||||
|
||||
|
||||
class _VaultSecretDataBlock(TypedDict, total=False):
|
||||
|
|
@ -368,6 +369,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
"url": url,
|
||||
"data_key": data_key,
|
||||
"secret_name": secret_name,
|
||||
"cache_key": f"{url}#{data_key}",
|
||||
}
|
||||
|
||||
def _get_request_headers(self) -> dict:
|
||||
|
|
@ -406,7 +408,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
)
|
||||
try:
|
||||
target: Final = self._build_secret_target(secret_name, optional_params)
|
||||
cached_value: Final = self.cache.get_cache(target["url"])
|
||||
cached_value: Final = self.cache.get_cache(target["cache_key"])
|
||||
if cached_value is not None:
|
||||
return cached_value
|
||||
|
||||
|
|
@ -415,7 +417,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
|
||||
json_resp: Final = _json_object_body(response)
|
||||
_value: Final = self._get_secret_value_from_json_response(json_resp, target["data_key"])
|
||||
self.cache.set_cache(target["url"], _value)
|
||||
self.cache.set_cache(target["cache_key"], _value)
|
||||
return _value
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -436,7 +438,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
sync_client: Final = _get_httpx_client()
|
||||
try:
|
||||
target: Final = self._build_secret_target(secret_name, optional_params)
|
||||
cached_value: Final = self.cache.get_cache(target["url"])
|
||||
cached_value: Final = self.cache.get_cache(target["cache_key"])
|
||||
if cached_value is not None:
|
||||
return cached_value
|
||||
|
||||
|
|
@ -445,7 +447,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
|
||||
json_resp: Final = _json_object_body(response)
|
||||
_value: Final = self._get_secret_value_from_json_response(json_resp, target["data_key"])
|
||||
self.cache.set_cache(target["url"], _value)
|
||||
self.cache.set_cache(target["cache_key"], _value)
|
||||
return _value
|
||||
|
||||
except Exception as e:
|
||||
|
|
@ -635,10 +637,10 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
)
|
||||
else:
|
||||
# Clear cache for the old secret only if deletion was successful
|
||||
self.cache.delete_cache(current_target["url"])
|
||||
self.cache.delete_cache(current_target["cache_key"])
|
||||
|
||||
# Clear cache for the new secret (or updated secret if names are the same)
|
||||
self.cache.delete_cache(new_target["url"])
|
||||
self.cache.delete_cache(new_target["cache_key"])
|
||||
|
||||
return create_response
|
||||
|
||||
|
|
@ -679,7 +681,7 @@ class HashicorpSecretManager(BaseSecretManager):
|
|||
response: Final = await async_client.delete(url=target["url"], headers=self._get_request_headers())
|
||||
response.raise_for_status()
|
||||
|
||||
self.cache.delete_cache(target["url"])
|
||||
self.cache.delete_cache(target["cache_key"])
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
|
|
|
|||
|
|
@ -120,6 +120,18 @@ def test_sync_read_caches_per_resolved_target(monkeypatch: pytest.MonkeyPatch) -
|
|||
assert team_b_route.call_count == 1
|
||||
|
||||
|
||||
@respx.mock
|
||||
def test_sync_read_caches_per_data_key_for_the_same_secret_path(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
manager: Final = _build_manager(monkeypatch, {"HCP_VAULT_SECRET_NAMESPACE": "teams/team-a"})
|
||||
respx.post(f"{VAULT_ADDR}/v1/auth/approle/login").respond(json=LOGIN_RESPONSE)
|
||||
respx.get(f"{VAULT_ADDR}/v1/teams/team-a/secret/data/DB_CREDS").respond(json=SECRET_RESPONSE)
|
||||
password_params: Final = {"secret_manager_settings": {"data": "password"}}
|
||||
|
||||
assert manager.sync_read_secret("DB_CREDS") == "sk-from-vault"
|
||||
assert manager.sync_read_secret("DB_CREDS", optional_params=password_params) == "pw-from-vault"
|
||||
assert manager.sync_read_secret("DB_CREDS") == "sk-from-vault"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@respx.mock
|
||||
async def test_async_read_uses_secret_namespace_and_login_namespace(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue