Ë
    tPêj}|  ã                   óÔ  — d Z ddlZddlmZmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZmZ ddlmZ ddlmZ dd	lmZ dd
lmZmZmZ ddlmZ ddlmZ ddlmZ erddlm Z! ddlm"Z"m#Z# de$e%e&f   dede$fd„Z' edd¬«       G d„ d«      «       Z(dee%e&f   de%dz  dede(fd„Z)de$de%dz  dedz  de%dz  fd„Z*de$dedz  fd„Z+de,e%   de,e%   fd„Z-d e	d!e%de.fd"„Z/d#e0e%   dedz  dd$fd%„Z1d#e0e%   dedz  de$e%e0e%   f   fd&„Z2d'ed(e$e%e0e%   f   ddfd)„Z3d'ed(e$e%e0e%   f   ddfd*„Z4d'edz  d(e$e%e0e%   f   ddfd+„Z5d(e$e%e0e%   f   de0e%   fd,„Z6	 dGd-d.dedz  de0e%   fd/„Z7de0e%   fd0„Z8de0e%   fd1„Z9d2e%dz  dedz  de,e%   fd3„Z:d4e,e%   dz  de%dz  d5e.dedz  ddf
d6„Z;d7ed.   dedz  de<e%   fd8„Z=	 dGd9ed:   dedz  de0e%   fd;„Z>d'edz  de0e%   fd<„Z?d'edz  de0e%   fd=„Z@d'edz  de0e%   fd>„ZA	 	 	 dHd'edz  d9ed:   dedz  d5e.d?ed.   dedz  fd@„ZBdAe0e%   d9ed:   d5e.ddfdB„ZCd'edz  de0e%   fdC„ZD	 dId'edz  d9ed:   d5e.ddfdD„ZEd'edz  de,e%   fdE„ZF	 dId'edz  d9ed:   d5e.ddfdF„ZGy)Jzh
Common utility functions for handling object permission updates across
organizations, teams, and keys.
é    N)ÚMappingÚSequence)Ú	dataclass)ÚTYPE_CHECKINGÚAnyÚFinalÚOptional)ÚHTTPExceptionÚstatus)Úverbose_proxy_logger)Úuuid)Ú
safe_dumps)ÚObjectPermissionDictÚSpecialMCPServerNameÚSpecialMCPServerNames)ÚPrismaClient)ÚObjectPermissionRepository)ÚMCPServerRepository)Úmodels)ÚLiteLLM_ObjectPermissionTableÚLiteLLM_TeamTableCachedObjÚ	data_dictÚprisma_clientÚreturnc              ƒ   ó  K  — |€t        d«      ‚| j                  d«      }|rGt        |«      j                  j	                  d|i¬«      ƒ d{  –—† }|r	 |j                  «       }|| d<   | S 7 Œ# t        $ r |j                  «       }Y Œ$w xY w­w)a–  
    Helper method to attach object_permission to a dictionary if object_permission_id is set.

    This function:
    1. Checks if the dictionary has an object_permission_id
    2. If found, queries the database for the corresponding object permission
    3. Converts the object permission to a dictionary format
    4. Attaches it to the input dictionary under the 'object_permission' key

    Args:
        data_dict: The dictionary to attach object_permission to
        prisma_client: The database client

    Returns:
        Dict: The input dictionary with object_permission attached if found

    Raises:
        ValueError: If prisma_client is None
    NúPrisma client not foundÚobject_permission_id©ÚwhereÚobject_permission)Ú
ValueErrorÚgetr   ÚtableÚfind_uniqueÚ
model_dumpÚ	ExceptionÚdict)r   r   r   r    s       ú}/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/management_helpers/object_permission_utils.pyÚ attach_object_permission_to_dictr)      s­   è ø€ ð. ÐÜÐ2Ó3Ð3à"+§-¡-Ð0FÓ"GÐÙÜ"<¸]Ó"K×"QÑ"Q×"]Ñ"]Ø)Ð+?Ð@ð #^ó #
÷ 
Ðñ ð=Ø$5×$@Ñ$@Ó$BÐ!ð .?ˆIÐ)Ñ*ØÐð
ùô ò =Ø$5×$:Ñ$:Ó$<Ò!ð=üs6   ‚ABÁA,ÁBÁA. Á%BÁ.B
ÂBÂ	B
Â
BT)ÚfrozenÚslotsc                   ó,   — e Zd ZU eed<   eeef   ed<   y)ÚObjectPermissionUpsertr   ÚrecordN)Ú__name__Ú
__module__Ú__qualname__ÚstrÚ__annotations__r'   Úobject© ó    r(   r-   r-   G   s   … àÓØ��f�ÑÔr6   r-   Únew_object_permissionÚexisting_object_permission_idc              ƒ   ó>  K  — |xs t        t        j                  «       «      }t        |«      j                  j                  d|i¬«      ƒ d{  –—† }|�|j                  dd¬«      ni }i |¥| ¥d|i¥}i |¥d|v rdt        |d   «      ini ¥}t        ||¬«      S 7 ŒL­w)a=  
    Read-and-merge half of an object permission upsert; performs no writes.

    Merges the sent grants over the existing row (looked up by
    ``existing_object_permission_id``, or a fresh uuid when the entity has none) and
    returns the id plus the full record to upsert. The id is pinned inside the record
    because the column has ``@default(uuid())``, so a create without it would mint a
    different id than the one the caller links. ``mcp_tool_permissions`` is serialized
    to a JSON string to avoid GraphQL parsing issues (e.g. server IDs starting with
    "3e64" being interpreted as floats).

    Keeping this separate from the write lets callers run the upsert inside the same
    transaction as the row that links ``object_permission_id``, so a rolled-back
    update cannot leave permission changes live.
    r   r   NT)Úexclude_unsetÚexclude_noneÚmcp_tool_permissions)r   r.   )	r2   r   Úuuid4r   r#   r$   r%   r   r-   )r7   r8   r   r   Úexisting_object_permissionÚexisting_fieldsÚmergedr.   s           r(   Ú prepare_object_permission_upsertrA   M   sä   è ø€ ð( #@Ò"TÄ3ÄtÇzÁzÃ|ÓCTÐÜ.HÈÓ.W×.]Ñ.]×.iÑ.iØ%Ð';Ð<ð /jó /÷ )Ðð
 &Ð1ð 	#×-Ñ-¸DÈtÐ-ÔTàð ð
(Ø
ð(à
ð(ð 	Ð 4ñ(€Fð
(Ø
ð(ð &¨Ñ/ð $¤Z°Ð7MÑ0NÓ%OÑPàð(€Fô "Ð7KÐTZÔ[Ð[ð+)ús   ‚ABÁBÁABÚ	data_jsonc              ƒ   óÖ  K  — |€t        d«      ‚| j                  dd«      }|€yt        |t        «      rt	        j
                  |«      }t        t        |t        «      r|ni ||¬«      ƒ d{  –—† }t        |«      j                  j                  d|j                  i|j                  |j                  dœ¬«      ƒ d{  –—† }t        j                  d|«       |j                  S 7 Œw7 Œ(­w)	a  
    Common logic for handling object permission updates across organizations, teams, and keys.

    This function:
    1. Extracts `object_permission` from data_json
    2. Looks up existing object permission if it exists
    3. Merges new permissions with existing ones
    4. Upserts to the LiteLLM_ObjectPermissionTable
    5. Returns the object_permission_id

    Args:
        data_json: The data dictionary containing the object_permission to update
        existing_object_permission_id: The current object_permission_id from the entity (can be None)
        prisma_client: The database client

    Returns:
        Optional[str]: The object_permission_id after the update/creation, or None if no object_permission to process

    Raises:
        ValueError: If prisma_client is None
    Nr   r    )r7   r8   r   r   )ÚcreateÚupdate)r   Údataz!created_object_permission_row: %s)r!   ÚpopÚ
isinstancer2   ÚjsonÚloadsrA   r'   r   r#   Úupsertr   r.   r   Údebug)rB   r8   r   r7   rK   Úcreated_object_permission_rows         r(   Ú&handle_update_object_permission_commonrN   z   sî   è ø€ ð4 ÐÜÐ2Ó3Ð3à/8¯}©}Ð=PÐRVÓ/WÐØÐ$ØäÐ'¬Ô-Ü $§
¡
Ð+@Ó AÐä:Ü7AÐBWÔY]Ô7^Ñ3ÐdfØ&CØ#ô÷ €Fô
 2LÈMÓ1Z×1`Ñ1`×1gÑ1gØ% v×'BÑ'BÐCà—m‘mØ—m‘mñ
ð 2hó 2÷ ,Ð!ô ×ÑÐBÐDaÔbà(×=Ñ=Ð=ðøð
,ús%   ‚A+C)Á-C%Á.AC)Â>C'Â?'C)Ã'C)c              ƒ   óš  K  — |�d| vr| S | d   }t        |t        «      s| j                  d«       | S |j                  «       D ��ci c]  \  }}|€Œ	|dk7  sŒ||“Œ }}}d|v rt	        |d   «      |d<   t        |«      j                  j                  |¬«      ƒ d{  –—† }|j                  | d<   | j                  d«       | S c c}}w 7 Œ,­w)z‡
    Creates the LiteLLM_ObjectPermissionTable record for the key/team.
    Handles permissions for vector stores and mcp servers.
    Nr    r   r<   )rF   )	rH   r'   rG   Úitemsr   r   r#   rD   r   )rB   r   Úpermission_dataÚkÚvÚ
clean_dataÚcreated_permissions          r(   Ú_set_object_permissionrV   °   sï   è ø€ ð ÐÐ 3¸9Ñ DØÐà&Ð':Ñ;€OÜ�o¤tÔ,Ø�‰Ð)Ô*ØÐð )×.Ñ.Ó0÷,Ù��A°A±MÀaÐKaÓFaˆˆ1‰ð,€Jñ ,ð
  Ñ+Ü-7¸
ÐCYÑ8ZÓ-[ˆ
Ð)Ñ*ä&@ÀÓ&O×&UÑ&U×&\Ñ&\ÐblÐ&\Ó&m× mÐà(:×(OÑ(O€IÐ$Ñ%Ø‡M�MÐ%Ô&ØÐùó,ð !nús+   ‚ACÁ
CÁCÁCÁA CÂC	Â-CÚvaluesc                 óz   — t        «       }g }| D ])  }||v rŒ|j                  |«       |j                  |«       Œ+ |S ©N)ÚsetÚaddÚappend)rW   ÚseenÚresultÚvalues       r(   Ú_dedupe_preserving_orderr`   Ð   sE   € Ü›E€DØ!€FØò ˆØ�D‰=ØØ�‰�ŒØ�‰�eÕð	ð
 €Mr6   ÚserverÚ
identifierc           	      ój   — |t        | dd «      t        | dd «      t        | dd «      t        | dd «      hv S )NÚ	server_idÚaliasÚserver_nameÚname)Úgetattr)ra   rb   s     r(   Ú_mcp_server_identifier_matchesri   Û   sD   € ØÜ�˜ TÓ*Ü�˜ Ó&Ü�˜ tÓ,Ü�˜ Ó%ð	ð ð r6   Úidentifiersz.Sequence[prisma_models.LiteLLM_MCPServerTable]c              ƒ   ó¬   K  — |�| sg S t        | «      }t        |«      j                  j                  ddd|iidd|iidd|iigi¬«      ƒ d {  –—† S 7 Œ­w)NÚORrd   Úinre   rf   r   )Úlistr   r#   Ú	find_many)rj   r   Úidentifier_lists      r(   Ú"_get_db_mcp_servers_by_identifiersrq   ä   s�   è ø€ ð Ð¡KØˆ	ä! +Ó.€OÜ$ ]Ó3×9Ñ9×CÑCàØ˜t _Ð5Ð6Ø˜4 Ð1Ð2Ø  Ð 7Ð8ðð
ð Dó ÷ ð ð ús   ‚AAÁAÁAc              ƒ   óÒ  K  — | si S ddl m} | D �ci c]  }|t        «       “Œ }}t        | |¬«      ƒ d{  –—† D ]:  }t	        |dd«      }|sŒ| D ]#  }t        ||«      sŒ||   j                  |«       Œ% Œ< |j                  «       j                  «       D ]F  \  }}t	        |dd«      xs |}|sŒ| D ](  }||k(  st        ||«      sŒ||   j                  |«       Œ* ŒH |S c c}w 7 Œ¯­w)a  
    Resolve MCP permission entries written as server_id, alias, or server_name
    to canonical server IDs.

    DB rows are authoritative when available; the in-memory registry is still
    consulted for config-file servers, which are not persisted in the MCP table.
    r   ©Úglobal_mcp_server_manager©rj   r   Nrd   )	Ú9litellm.proxy._experimental.mcp_server.mcp_server_managerrt   rZ   rq   rh   ri   r[   Úget_registryrP   )rj   r   rt   rb   Úresolvedra   rd   Úregistry_keys           r(   Ú&_resolve_mcp_server_identifiers_to_idsrz   ÷   s  è ø€ ñ Øˆ	õð Q\Ö+\À*¨J¼»Ñ,=Ð+\€HÐ+\ä:ØØ#ô÷ ò 	4ˆô ˜F K°Ó6ˆ	ÙØØ%ò 	4ˆJÜ-¨f°jÕAØ˜Ñ$×(Ñ(¨Õ3ñ	4ð	4ð !:× FÑ FÓ H× NÑ NÓ Pò 4Ñˆ�fÜ˜F K°Ó6ÒF¸,ˆ	ÙØØ%ò 	4ˆJØ˜\Ò)Ô-KÈFÐT^Õ-_Ø˜Ñ$×(Ñ(¨Õ3ñ	4ð	4ð €Oùò+ ,]ðús&   ‚C'‘C £C'µC%¶(C'ÁA&C'Ã C'r    Úidentifier_to_server_idsc           	      óX  — | j                  d«      }t        |t        «      sy g }|D ]s  }|t        j                  j
                  k(  r*|j                  t        j                  j
                  «       ŒJ|j                  t        |j                  |g «      «      «       Œu t        |«      | d<   y )NÚmcp_servers)
r"   rH   rn   r   Úno_mcp_serversr_   r\   ÚextendÚsortedr`   )r    r{   r}   Únormalized_serversrb   s        r(   Ú&_rewrite_object_permission_mcp_serversr‚   !  s¡   € ð +×.Ñ.¨}Ó=€KÜ�k¤4Ô(Øà+-ÐØ!ò Xˆ
ØÔ.×=Ñ=×CÑCÒCØ×%Ñ%Ô&;×&JÑ&J×&PÑ&PÔQØØ×!Ñ!¤&Ð)A×)EÑ)EÀjÐRTÓ)UÓ"VÕWð	Xô
 (@Ð@RÓ'SÐ�mÒ$r6   c                 ó˜  — | j                  d«      }t        |t        «      sy i }|j                  «       D ]]  \  }}t        |t        «      sg }t        |j                  |g «      «      D ](  }|j                  |g «       ||   j                  |«       Œ* Œ_ |j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}| d<   y c c}}w )Nr<   )	r"   rH   r'   rP   rn   r€   Ú
setdefaultr   r`   )r    r{   r<   Únormalized_tool_permissionsrb   Útoolsrd   s          r(   Ú/_rewrite_object_permission_mcp_tool_permissionsr‡   2  sÜ   € ð #4×"7Ñ"7Ð8NÓ"OÐÜÐ*¬DÔ1Øà?AÐØ1×7Ñ7Ó9ò AÑˆ
�EÜ˜%¤Ô&ØˆEÜÐ 8× <Ñ <¸ZÈÓ LÓMò 	AˆIØ'×2Ñ2°9¸bÔAØ'¨	Ñ2×9Ñ9¸%Õ@ñ	AðAð Lg×KlÑKlÓKn÷1Ù7G°yÀ%ˆ	Ô+¨EÓ2Ñ2ó1ÐÐ,Ò-ùó 1s   Â(Cc                 ó^   — | rt        | t        «      sy t        | |¬«       t        | |¬«       y )N©r    r{   )rH   r'   r‚   r‡   r‰   s     r(   Ú*_rewrite_object_permission_mcp_identifiersrŠ   G  s2   € ñ ¤JÐ/@Ä$Ô$GØä*Ø+Ø!9õô 4Ø+Ø!9ör6   c                 ó\   — | j                  «       D ��ch c]  }|D ]  }|’Œ Œ c}}S c c}}w rY   )rW   )r{   Ú
server_idsrd   s      r(   Ú _flatten_resolved_mcp_server_idsr�   X  s/   € ð )A×(GÑ(GÓ(I×f˜*Ð[eÒfÈiŠIÐfˆIÓfÐfùÓfs   ”(Úteam_object_permissionr   c              ƒ   ó(  K  — ddl m} | j                  xs g }t        j                  j
                  |v r
t        «       S |j                  | j                  xs g «      ƒ d{  –—† }| j                  xs i }t        |t        «      rt        j                  |«      }t        |j                  «       «      }t!        ||z   |z   «      }t#        ||¬«      ƒ d{  –—† }|D �	ch c]  }	|j%                  |	«      rŒ|	’Œ }
}	t'        |«      |
z  S 7 Œ§7 Œ5c c}	w ­w)zÑ
    Resolve the full set of MCP server IDs a team has access to.

    Combines:
    - Direct mcp_servers list
    - Servers from mcp_access_groups
    - Server IDs referenced in mcp_tool_permissions keys
    r   )ÚMCPRequestHandlerNru   )ÚAlitellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcpr�   r}   r   Úall_proxy_serversr_   Ú_get_all_mcp_server_idsÚ#_get_mcp_servers_from_access_groupsÚmcp_access_groupsr<   rH   r2   rI   rJ   rn   ÚkeysrZ   rz   r"   r�   )rŽ   r   r�   Údirect_serversÚaccess_group_serversÚraw_tool_permsÚtool_perm_serversÚraw_serversÚresolved_serversrd   Úunresolved_serverss              r(   Ú!_resolve_team_allowed_mcp_serversrž   ^  s  è ø€ õð (>×'IÑ'IÒ'OÈR€NÜ×-Ñ-×3Ñ3°~ÑEÜ&Ó(Ð(Ø3D×3hÑ3hØ×0Ñ0Ò6°Bó4÷ .Ðð ,×@Ñ@ÒFÀB€NÜ�.¤#Ô&ÜŸ™ NÓ3ˆÜ*.¨~×/BÑ/BÓ/DÓ*EÐÜ˜^Ð.BÑBÐEVÑVÓW€KÜ$JØØ#ô%÷ Ðð =HÖ o¨yÐO_×OcÑOcÐdmÕOn¢Ð oÐÐ oÜ+Ð,<Ó=Ð@RÑRÐRð.øðúò !pùs=   ‚ADÁ!D	Á"A3DÃDÃDÃDÃ5DÃ9DÄDÄDc                  ó@   — ddl m}  t        | j                  «       «      S )zAReturn the set of MCP server IDs marked with allow_all_keys=True.r   rs   )rv   rt   rZ   Úget_allow_all_keys_server_idsrs   s    r(   Ú_get_allow_all_keys_server_idsr¡   �  s   € õô Ð(×FÑFÓHÓIÐIr6   c                  ó\   — ddl m}  t        | j                  «       j	                  «       «      S )zGReturn every MCP server id registered on the proxy (config + DB union).r   rs   )rv   rt   rZ   rw   r–   rs   s    r(   r“   r“   Š  s'   € õô Ð(×5Ñ5Ó7×<Ñ<Ó>Ó?Ð?r6   r   c              ƒ   ó    K  — | r|€g S t        |«      j                  j                  d| i¬«      ƒ d {  –—† }|€g S |j                  xs g S 7 Œ­w)Nr   r   )r   r#   r$   r}   )r   r   Úexistings      r(   Ú'_existing_object_permission_mcp_serversr¥   “  sg   è ø€ ñ   =Ð#8Øˆ	Ü6°}ÓE×KÑK×WÑWØ%Ð';Ð<ð Xó ÷ €Hð ÐØˆ	Ø×ÑÒ% 2Ð%ðús   ‚1A³A´AÚrequested_mcp_serversÚis_proxy_adminc              ƒ   óÆ   K  — t         j                  j                  }|s|| xs g vryt        ||¬«      ƒ d{  –—† }||v ryt	        t
        j                  ddi¬«      ‚7 Œ&­w)aß  
    Only a proxy admin may newly grant the all-proxy MCP sentinel.

    Scoping a team to every MCP server on the proxy is a proxy-wide authorization
    decision, so a caller who is not a proxy admin (e.g. a team admin managing their
    own team) cannot add ``all-proxy-mcpservers``. A sentinel a proxy admin already
    granted is left untouched, so unrelated edits to such a team still succeed.

    Raises HTTPException(403) when a non-admin tries to add the sentinel.
    N)r   r   Úerrorz]Only a proxy admin can grant a team access to all proxy MCP servers ('all-proxy-mcpservers').©Ústatus_codeÚdetail)r   r’   r_   r¥   r
   r   ÚHTTP_403_FORBIDDEN)r¦   r8   r§   r   ÚsentinelÚexisting_mcp_serverss         r(   Ú1enforce_all_proxy_mcp_servers_grant_is_admin_onlyr°   ¡  sv   è ø€ ô  +×<Ñ<×BÑB€HÙ˜Ð*?Ò*EÀ2ÑFØÜ(OØ:Ø#ô)÷ #Ðð Ð'Ñ'ØÜ
Ü×-Ñ-àÐtð
ôð ð#ús   ‚6A!¸A¹'A!r>   c           	   ƒ   óä  K  — | �|€
t        «       S | j                  xs i }t        t        |t        «      r#t	        j
                  |«      j                  «       n|j                  «       «      }t        | j                  xs g «      |z  t        j                  j                  t        j                  j                  hz
  }t        t        t        t        |«      |¬«      ƒ d{  –—† «      «      S 7 Œ­w)a  
    Resolve the canonical MCP server IDs a key's stored object_permission already
    grants. Updates that keep or shrink those grants stay valid even when the
    team allowlist has since changed; sentinels are excluded so they cannot
    grandfather anything.
    Nru   )Ú	frozensetr<   rH   r2   rI   rJ   r–   r}   r   r~   r_   r   r’   r�   rz   rZ   )r>   r   r™   Útool_perm_keysrj   s        r(   Ú%_get_grandfathered_key_mcp_server_idsr´   Â  sÚ   è ø€ ð "Ð)¨]Ð-BÜ‹{ÐØ6×KÑKÒQÈr€NÜ,5Ü-7¸ÌÔ-LŒ�
‰
�>Ó"×'Ñ'Ô)ÐR`×ReÑReÓRgó-€Nô $Ð$>×$JÑ$JÒ$PÈbÓQÐTbÑbÜ×,Ñ,×2Ñ2Ü×.Ñ.×4Ñ4ðgñ €Kô Ü(Ü8Ü Ó,Ø+ô÷ ó	
óð ðús   ‚CC0Ã!C.Ã"C0Úteam_objr   c              ƒ   ó€   K  — | €
t        «       S | j                  }|€
t        «       S t        ||¬«      ƒ d{  –—† S 7 Œ­w)z¾
    Get the full set of MCP server IDs a team allows.

    If team has no object_permission or no MCP config, returns empty set
    (meaning only allow_all_keys servers are permitted).
    N)rŽ   r   )rZ   r    rž   )rµ   r   rŽ   s      r(   Ú_get_team_allowed_mcp_serversr·   à  sK   è ø€ ð ÐÜ‹uˆà$,×$>Ñ$>ÐØÐ%Ü‹uˆä2Ø5Ø#ô÷ ð ð ús   ‚5>·<¸>c                 óˆ  — | rt        | t        «      s
t        «       S t        «       }| j                  d«      }t        |t        «      r:|j                  |«       |j                  t        j                  j                  «       | j                  d«      }t        |t        «      r|j                  |j                  «       «       |S )z�
    Extract all MCP server IDs referenced in a key's object_permission dict.

    Includes:
    - mcp_servers list
    - Keys from mcp_tool_permissions
    r}   r<   )rH   r'   rZ   r"   rn   rE   Údiscardr   r~   r_   r–   )r    rŒ   r}   r<   s       r(   Ú!_extract_requested_mcp_server_idsrº   ÷  s�   € ñ ¤JÐ/@Ä$Ô$GÜ‹uˆä"%£%€JØ*×.Ñ.¨}Ó=€KÜ�+œtÔ$Ø×Ñ˜+Ô&Ø×ÑÔ0×?Ñ?×EÑEÔFà"3×"7Ñ"7Ð8NÓ"OÐÜÐ&¬Ô-Ø×ÑÐ.×3Ñ3Ó5Ô6àÐr6   c                 ó¦   — | rt        | t        «      s
t        «       S | j                  d«      }t        |t        «      rt        |«      S t        «       S )z>Extract MCP access groups from a key's object_permission dict.r•   ©rH   r'   rZ   r"   rn   )r    Úgroupss     r(   Ú$_extract_requested_mcp_access_groupsr¾     sD   € ñ ¤JÐ/@Ä$Ô$GÜ‹uˆà%×)Ñ)Ð*=Ó>€FÜ�&œ$ÔÜ�6‹{ÐÜ‹5€Lr6   c                 ó¦   — | rt        | t        «      s
t        «       S | j                  d«      }t        |t        «      rt        |«      S t        «       S )z<Extract MCP toolset IDs from a key's object_permission dict.Úmcp_toolsetsr¼   )r    Útoolsetss     r(   Ú_extract_requested_mcp_toolsetsrÂ     sC   € ñ ¤JÐ/@Ä$Ô$GÜ‹uˆà'×+Ñ+¨NÓ;€HÜ�(œDÔ!Ü�8‹}ÐÜ‹5€Lr6   Úexisting_key_object_permissionc           
   ƒ   óv  K  — |du xr |}t        | «      }t        | «      }t        | «      }|s|s|s| S t        «       }	t	        ||¬«      ƒ d{  –—† }
|
|	z  }|�rt        ||¬«      ƒ d{  –—† }|D �ch c]  }|j                  |«      rŒ|’Œ }}|rt        j                  dt        |«      «       t        | |¬«       t        |«      }|}|r||z  }t        ||¬«      ƒ d{  –—† }||z
  |z
  }|rq|�7|j                  }d|› dt        |«      › d	t        |
«      › d
t        |	«      › d�	}ndt        |	«      › dt        |«      › d�}t        t        j                   d|i¬«      ‚|r¶t#        «       }|�A|j$                  �5|j$                  j&                  rt#        |j$                  j&                  «      }|}|r||z  }||z
  }|rY|�+|j                  }d|› dt        |«      › d	t        |«      › d�}ndt        |«      › d�}t        t        j                   d|i¬«      ‚t)        |||¬«       | S 7 �ŒÝ7 �ŒÃc c}w 7 �ŒS­w)a'  
    Validate that MCP servers requested on a key are within the allowed scope.

    When ``existing_key_object_permission`` is provided (key updates), servers
    the key already holds are grandfathered: keeping or removing them stays valid
    even if the team allowlist has since shrunk, while adding new servers outside
    the allowlist is still rejected.

    Rules:
    - If key is in a team: key's mcp_servers must be a subset of
      (team's allowed servers + allow_all_keys servers)
    - If key is NOT in a team and the caller is a proxy admin: any server or
      access group may be assigned. A proxy admin can already reach every MCP
      server, and runtime access is granted directly from the key's own
      object_permission, so the key is scoped to exactly what the admin selected
    - If key is NOT in a team and the caller is not a proxy admin: key's
      mcp_servers must only contain allow_all_keys servers
    - If team has no MCP config: key can only use allow_all_keys servers

    Raises HTTPException(403) if validation fails.
    N)rµ   r   ru   znvalidate_key_mcp_servers_against_team: ignoring stale MCP server identifiers (no longer in registry or DB): %sr‰   )r>   r   z.Key requests MCP servers not allowed by team 'ú': ú. Team allows: z#. Global (allow_all_keys) servers: ú.z\Key is not in a team. Only globally available (allow_all_keys) MCP servers can be assigned: z. Disallowed servers: r©   rª   z4Key requests MCP access groups not allowed by team 'ziKey is not in a team. MCP access groups cannot be assigned to keys outside of a team. Disallowed groups: )Úrequested_toolsetsrµ   r§   )rº   r¾   rÂ   r¡   r·   rz   r"   r   Úwarningr€   rŠ   r�   r´   Úteam_idr
   r   r­   rZ   r    r•   Ú_validate_requested_toolsets)r    rµ   r   r§   rÃ   Úteamless_admin_assignmentÚrequested_serversÚrequested_access_groupsrÈ   Úallow_all_keys_serversÚteam_allowed_serversÚall_allowed_serversr{   rb   Ústale_identifiersÚactive_requested_serversÚallowed_serversÚgrandfathered_serversÚdisallowed_serversrÊ   r¬   Úteam_access_groupsÚallowed_access_groupsÚdisallowed_groupss                           r(   Ú%validate_key_mcp_servers_against_teamrÚ   +  s
  è ø€ ð8 (0°4Ð'7Ò'J¸NÐÜ@ÐARÓSÐÜ%IÐJ[Ó%\Ðä ?Ð@QÓ RÐñ Ñ%<ÑEWØ Ð ä$BÓ$DÐÜ(EØØ#ô)÷ #Ðð "6Ð8NÑ!NÐò ô 1WØ)Ø'ô1
÷ +
Ð ð
 *;ö$
Ø%ÐBZ×B^ÑB^Ð_iÕBjŠJð$
Ðð $
ñ Ü ×(Ñ(ð AÜÐ(Ó)ôô 	3Ø/Ø%=õ	
ô +KÐKcÓ*dÐ à-ˆÙ$Ø1Ð4LÑLˆOä-RØ'EØ'ô.
÷ (
Ðð %=¸Ñ$NÐQfÑ$fÐÙØÐ#Ø"×*Ñ*�àDÀWÀIÈSÜÐ0Ó1Ð2ð 3$Ü$*Ð+?Ó$@Ð#Að B8Ü8>Ð?UÓ8VÐ7WÐWXðZñ ð(Ü(.Ð/EÓ(FÐ'Gð H+Ü+1Ð2DÓ+EÐ*FÀaðIð ô
  Ü"×5Ñ5Ø Ð(ôð ñ Ü'*£uÐàÐ Ø×*Ñ*Ð6Ø×*Ñ*×<Ò<ä!$ X×%?Ñ%?×%QÑ%QÓ!RÐà 2ÐÙ$Ø$6Ð9PÑ$PÐ!à#:Ð=RÑ#RÐÙØÐ#Ø"×*Ñ*�àJÈ7È)ÐSVÜÐ/Ó0Ð1ð 2$Ü$*Ð+=Ó$>Ð#?¸qðBñ ðBÜBHÐIZÓB[ÐA\Ð\]ð_ð ô  Ü"×5Ñ5Ø Ð(ôð ô
 !Ø-ØØ%õð ÐðE#ùð+
ûò$
ð$(
ûsJ   ‚AH9ÁH+ÁH9Á+H.Á,H9Á4H1ÂH1ÂAH9Ã#H6Ã$EH9È.H9È1H9rÈ   c                 óL  — | sy|€-|ryt        t        j                  ddt        | «      › d�i¬«      ‚|j                  }|�|j
                  nd}|sy| t        |«      z
  }|syt        t        j                  dd|j                  › dt        |«      › dt        |«      › d�i¬«      ‚)	zÇ
    Validate mcp_toolsets requested on a key.

    Non-admin callers cannot assign toolsets to a personal (no team) key. Team
    keys must request a subset of the team's own toolset allowlist.
    Nr©   zrKey is not in a team. MCP toolsets cannot be assigned to personal keys by non-admin callers. Disallowed toolsets: rÇ   rª   z/Key requests MCP toolsets not allowed by team 'rÅ   rÆ   )r
   r   r­   r€   r    rÀ   rZ   rÊ   )rÈ   rµ   r§   Úteam_opÚteam_mcp_toolsetsÚdisallowed_toolsetss         r(   rË   rË   ·  sÞ   € ñ ØØÐÙØÜÜ×1Ñ1àðPäÐ0Ó1Ð2°!ð5ðô	
ð 		
ð ×/Ñ/€GØ7>Ð7J˜w×3Ò3ÐPTÐÙØØ!3´cÐ:KÓ6LÑ!LÐÙØÜ
Ü×-Ñ-àØAÀ(×BRÑBRÐASÐSVÜÐ-Ó.Ð/ð 0 Ü &Ð'8Ó 9Ð:¸!ð=ð
ô	ð 	r6   c                 óÒ   — | rt        | t        «      s
t        «       S | j                  d«      }t        |t        «      r|D �ch c]  }|sŒt        |«      ’Œ c}S t        «       S c c}w )z<Return vector_store IDs from a key's object_permission dict.Úvector_stores)rH   r'   rZ   r"   rn   r2   ©r    ÚrawÚxs      r(   Ú _extract_requested_vector_storesrä   ä  sU   € ñ ¤JÐ/@Ä$Ô$GÜ‹uˆØ"×&Ñ& Ó7€CÜ�#”tÔØ #Ö)˜1¢q”�A•Ò)Ð)Ü‹5€Lùò *s   ÁA$Á
A$c              ƒ   ó„   K  — t        | «      }|sy|€|ryt        t        j                  ddt	        |«      › d�i¬«      ‚­w)a#  
    Reject vector_stores requested on a personal (no team) key by a non-admin
    caller. Vector store access is granted at use-time from the key's
    object_permission.vector_stores list, so the assignment is the authorization
    boundary. Team keys and proxy admins are unaffected.
    Nr©   zxKey is not in a team. Vector stores cannot be assigned to personal keys by non-admin callers. Disallowed vector stores: rÇ   rª   )rä   r
   r   r­   r€   )r    rµ   r§   Ú	requesteds       r(   Ú'validate_key_vector_stores_against_teamrç   ð  sZ   è ø€ ô 8Ð8IÓJ€IÙØØÐ™~ØÜ
Ü×-Ñ-àðQä˜)Ó$Ð% Qð(ð
ô	ð 	ùs   ‚>A c                 ó²   — | rt        | t        «      sg S | j                  d«      }t        |t        «      sg S |D �cg c]  }|sŒt	        |«      ‘Œ c}S c c}w )zCReturn search_tool_name values from a key's object_permission dict.Úsearch_tools)rH   r'   r"   rn   r2   rá   s      r(   Ú_extract_requested_search_toolsrê     sO   € ñ ¤JÐ/@Ä$Ô$GØˆ	Ø"×&Ñ& ~Ó6€CÜ�cœ4Ô Øˆ	ØÖ%�q¢1ŒC��FÒ%Ð%ùÒ%s   ¼AÁAc              ƒ   ó´  K  — t        | «      }|sy|€,|s*t        t        j                  ddt	        |«      › d�i¬«      ‚g }|�/|j
                  �#|j
                  j                  }|rt        |«      }|syt        |«      t        |«      z
  }|rI|�|j                  nd}t        t        j                  dd|› dt	        |«      › d	t	        |«      › d�i¬«      ‚y­w)
zí
    Validate key object_permission.search_tools is a subset of the team's allowlist.

    Empty team allowlist means no restriction at team layer (skip).
    Non-admin callers cannot assign search_tools to a personal (no team) key.
    Nr©   zvKey is not in a team. search_tools cannot be assigned to personal keys by non-admin callers. Disallowed search tools: rÇ   rª   Úunknownz/Key requests search tools not allowed by team 'rÅ   rÆ   )
rê   r
   r   r­   r€   r    ré   rn   rZ   rÊ   )r    rµ   r§   ræ   Ú
team_toolsÚstÚ
disallowedrÊ   s           r(   Ú&validate_key_search_tools_against_teamrð     s  è ø€ ô 7Ð7HÓI€IÙØàÐ¡ÜÜ×1Ñ1àðTä˜iÓ(Ð)¨ð,ðô	
ð 		
ð €JØÐ × :Ñ :Ð FØ×.Ñ.×;Ñ;ˆÙÜ˜b›ˆJáØä˜I›¬¨Z«Ñ8€JÙØ-5Ð-A˜×)Ò)ÀyˆÜÜ×1Ñ1àØEÀgÀYÈcÜ˜jÓ)Ð*¨/¼&ÀÓ:LÐ9MÈQðPðô
ð 	
ð ùs   ‚CCrY   )NFN)F)HÚ__doc__rI   Úcollections.abcr   r   Údataclassesr   Útypingr   r   r   r	   Úfastapir
   r   Úlitellm._loggingr   Úlitellm._uuidr   Ú*litellm.litellm_core_utils.safe_json_dumpsr   Úlitellm.proxy._typesr   r   r   Úlitellm.proxy.utilsr   Ú1litellm.repositories.object_permission_repositoryr   Ú'litellm.repositories.table_repositoriesr   Úprismar   Úprisma_modelsr   r   r'   r2   r4   r)   r-   rA   rN   rV   rn   r`   Úboolri   rZ   rq   rz   r‚   r‡   rŠ   r�   rž   r¡   r“   r¥   r°   r²   r´   r·   rº   r¾   rÂ   rÚ   rË   rä   rç   rê   rð   r5   r6   r(   ú<module>r      s2  ðñó
 ß -Ý !ß 6Ó 6ç )å 1Ý Ý Aß bÑ bÝ ,Ý XÝ GáÝ.÷ð&Ø�C˜�KÑ ð&àð&ð 
ó&ñR �$˜dÔ#÷ð ó $ðð
*\Ø" 3¨ ;Ñ/ð*\à#&¨¡:ð*\ð  ð*\ð ó	*\ðZ3>Øð3>à#&¨¡:ð3>ð   $Ñ&ð3>ð 	ˆ4�Zó	3>ðlØðà $Ñ&óð@ T¨#¡Yð °4¸±9ó ð¨3ð ¸Cð ÀDó ðØ�S‘ðà $Ñ&ðð 6óð&'Ø�S‘ð'à $Ñ&ð'ð 
ˆ#ˆs�3‰xˆ-Ñó'ðTTØ+ðTà" 3¨¨C© =Ñ1ðTð 
óTð"Ø+ðà" 3¨¨C© =Ñ1ðð 
óð*Ø+¨dÑ2ðà" 3¨¨C© =Ñ1ðð 
óð"gØ" 3¨¨C© =Ñ1ðgàˆ�Xógð *.ñ SØ;ð Sà $Ñ&ð Sð 	ˆ�Xó SðFJ¨¨C©ó Jð@  S¡ó @ð&Ø ™*ð&à $Ñ&ð&ð 
ˆ#�Yó&ðØ ™9 tÑ+ðà#&¨¡:ðð ðð   $Ñ&ð	ð
 
óðBØ (Ð)HÑ Iðà $Ñ&ðð ˆs�^óð@ *.ñØÐ3Ñ4ðà $Ñ&ðð 	ˆ�Xóð.Ø+¨dÑ2ðàˆ�Xóð4
Ø+¨dÑ2ð
àˆ�Xó
ð
Ø+¨dÑ2ð
àˆ�Xó
ð  *.Ø ØPTñIØ+¨dÑ2ðIàÐ3Ñ4ðIð   $Ñ&ðIð ð	Ið
 %-Ð-LÑ$MðIð ˜DÑ óIðX*Ø˜C™ð*àÐ3Ñ4ð*ð ð*ð 
ó	*ðZ	Ø+¨dÑ2ð	àˆ�Xó	ð !ñØ+¨dÑ2ðàÐ3Ñ4ðð ðð 
ó	ð8	&Ø+¨dÑ2ð	&à	ˆ#�Yó	&ð !ñ/
Ø+¨dÑ2ð/
àÐ3Ñ4ð/
ð ð/
ð 
ô	/
r6   