mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
defensive copies + clarifying comments in /health filter
- _filter_health_check_results_by_model_ids now shallow-copies each retained endpoint dict before returning. The shared module-level health_check_results cache should never be mutated by downstream transforms, even though _strip_admin_only_fields_from_health_result already builds new dicts today. - Document the live (model_name) vs cache (model_id) scoping asymmetry so future readers do not have to derive it from the warnings field. - Document why _PROXY_ADMIN_ROLES includes PROXY_ADMIN_VIEW_ONLY (read- only operators need routing fields to diagnose health). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5a4075b2bd
commit
38c72a5993
1 changed files with 17 additions and 2 deletions
|
|
@ -728,6 +728,10 @@ async def _save_background_health_checks_to_db(
|
|||
_PROXY_ADMIN_ROLES = frozenset(
|
||||
{
|
||||
LitellmUserRoles.PROXY_ADMIN.value,
|
||||
# View-only admins are operators (oncall, support); they need the
|
||||
# routing fields (api_base, api_version) to diagnose health and tell
|
||||
# which provider region a check is hitting. They cannot mutate config
|
||||
# so granting them the read-only view is safe.
|
||||
LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY.value,
|
||||
}
|
||||
)
|
||||
|
|
@ -782,14 +786,18 @@ def _filter_health_check_results_by_model_ids(
|
|||
Endpoints without a model_id (e.g. CLI-model entries that predate the
|
||||
model_id wiring) are dropped conservatively — we cannot prove they belong
|
||||
to the caller, so they are excluded rather than leaked.
|
||||
|
||||
Each retained endpoint is shallow-copied before being returned, so any
|
||||
downstream transform (e.g. _strip_admin_only_fields_from_health_result)
|
||||
cannot accidentally mutate the shared ``health_check_results`` cache.
|
||||
"""
|
||||
healthy = [
|
||||
ep
|
||||
dict(ep)
|
||||
for ep in (results.get("healthy_endpoints") or [])
|
||||
if ep.get("model_id") in allowed_model_ids
|
||||
]
|
||||
unhealthy = [
|
||||
ep
|
||||
dict(ep)
|
||||
for ep in (results.get("unhealthy_endpoints") or [])
|
||||
if ep.get("model_id") in allowed_model_ids
|
||||
]
|
||||
|
|
@ -954,6 +962,13 @@ async def health_endpoint(
|
|||
)
|
||||
_llm_model_list = copy.deepcopy(llm_model_list)
|
||||
### FILTER MODELS FOR ONLY THOSE USER HAS ACCESS TO ###
|
||||
# Live path: scope by model_name (every deployment has one).
|
||||
# Cache path: scope by model_id (the cache is keyed on model_id).
|
||||
# Consequence: a deployment whose model_name the caller can access
|
||||
# but which lacks model_info.id will appear in the live /health
|
||||
# response but NOT in the background-cache /health response. This is
|
||||
# surfaced via the "warnings" field below so operators can fix the
|
||||
# missing model_info.id rather than guess at the discrepancy.
|
||||
if len(user_api_key_dict.models) > 0:
|
||||
allowed_models = set(user_api_key_dict.models)
|
||||
_llm_model_list = [
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue