Ë
    uPêjû<  ã                   óò  — U d Z ddlZddlmZ ddlmZmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddl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!m"Z"m#Z#m$Z$ erddl%m&Z'  e«       Z(ee)d<   de*dee*   de+e*e,f   fd„Z-de,de+fd„Z.d7de,de,de/fd„Z0de,ddfd„Z1ddd ee*   de2e/e*   e3f   fd!„Z4d"dd ee*   de2e/e*   e3f   fd#„Z5de,d$dd%ee*   d&ee*   d'ee*   de2e/e*   e/e*   e3f   fd(„Z6de,d)ee*   d'ee*   de/e*   fd*„Z7e(jq                  d+d,g e	e«      ge$¬-«       ed.d/¬0«       e	e«      fd1e#d2e9d3efd4„«       Z:e(jq                  d5d,g e	e«      ge¬-«       e	e«      fd1e d3efd6„«       Z;y)8uå   
Policy resolve and attachment impact estimation endpoints.

- /policies/resolve â€” debug which guardrails apply for a given context
- /policies/attachments/estimate-impact â€” preview blast radius before creating an attachment
é    N)ÚSequence)ÚTYPE_CHECKINGÚFinal)Ú	APIRouterÚDependsÚHTTPExceptionÚQuery)Úverbose_proxy_logger)ÚMAX_POLICY_ESTIMATE_IMPACT_ROWS)ÚUserAPIKeyAuth)ÚRouteChecks)Úuser_api_key_auth)Úget_attachment_registry)Úget_policy_registry)ÚTeamRepository)ÚVerificationTokenRepository)ÚAttachmentImpactResponseÚPolicyAttachmentCreateRequestÚPolicyMatchContextÚPolicyMatchDetailÚPolicyResolveRequestÚPolicyResolveResponse)ÚmodelsÚrouterÚfieldÚpatternsÚreturnc                 ó   — g }g }|D ]=  }|j                  d«      r|j                  | d|dd ii«       Œ-|j                  |«       Œ? g }|r|j                  | d|ii«       |j                  |«       |s| ddiiS t        |«      dk(  r|d   S d	|iS )
zæBuild a Prisma ``where`` clause for alias patterns.

    Supports exact matches and suffix wildcards (``prefix*``).
    Returns something like:
        {"OR": [{"field": {"in": ["a","b"]}}, {"field": {"startsWith": "dev-"}}]}
    Ú*Ú
startsWithNéÿÿÿÿÚinÚnoté   r   ÚOR)ÚendswithÚappendÚextendÚlen)r   r   ÚexactÚprefix_conditionsÚpatÚ
conditionss         úy/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/policy_engine/policy_resolve_endpoints.pyÚ_build_alias_wherer/   (   s·   € ð !€EØ8:ÐØò ˆØ�<‰<˜ÔØ×$Ñ$ e¨l¸CÀÀ¸HÐ-EÐ%FÕGà�L‰L˜Õð	ð 24€JÙØ×Ñ˜5 4¨ -Ð0Ô1Ø×ÑÐ'Ô(áØ˜˜t�}Ð%Ð%Ü
ˆ:ƒ˜!ÒØ˜!‰}ÐØ�*ÐÐó    Úraw_metadatac                 óÀ   — | €i S t        | t        «      r	 t        j                  | «      S t        | t        «      r| S i S # t        j                  t
        f$ r i cY S w xY w)z8Parse metadata that may be a dict, JSON string, or None.)Ú
isinstanceÚstrÚjsonÚloadsÚJSONDecodeErrorÚ	TypeErrorÚdict)r1   s    r.   Ú_parse_metadatar:   C   sb   € àÐØˆ	Ü�,¤Ô$ð	Ü—:‘:˜lÓ+Ð+ô & l´DÔ9ˆ<ÐA¸rÐAøô ×$Ñ$¤iÐ0ò 	ØŠIð	ús   –? ¿AÁAÚmetadataÚjson_metadatac                 óP   — |�|n| }t        |«      }|j                  dg «      xs g S )zDExtract tags list from a metadata field (or metadata_json fallback).Útags)r:   Úget)r;   r<   ÚrawÚparseds       r.   Ú_get_tags_from_metadatarB   O   s.   € à"/Ð";‘À€CÜ# CÓ(€FØ�:‰:�f˜bÓ!Ò' RÐ'r0   Úprisma_clientz)Sequence[prisma_models.LiteLLM_TeamTable]c              ƒ   óx   K  — t        | «      j                  j                  i ddit        ¬«      ƒ d{  –—† S 7 Œ­w)zHFetch teams from DB once. Reuse the result across tag and alias lookups.Ú
created_atÚdesc©ÚwhereÚorderÚtakeN)r   ÚtableÚ	find_manyr   ©rC   s    r.   Ú_fetch_all_teamsrN   V   sA   è ø€ ä Ó.×4Ñ4×>Ñ>ØØ˜VÐ$Ü,ð ?ó ÷ ð ð ús   ‚1:³8´:Úkeysz1Sequence[prisma_models.LiteLLM_VerificationToken]Útag_patternsc           	      óæ   ‡— g }d}| D ]d  }|j                   xs d}t        |j                  t        |dd«      «      }|sŒ7t	        ˆfd„|D «       «      sŒL|r|j                  |«       Œ`|dz  }Œf ||fS )zvFilter key rows whose metadata.tags match any of the given patterns.

    Returns (named_aliases, unnamed_count).
    r   Ú Úmetadata_jsonNc              3   óZ   •K  — | ]"  }‰D ]  }t        j                  ||¬ «      –— Œ Œ$ y­w©)ÚrouteÚpatternN©r   Úroute_matches_wildcard_pattern©Ú.0Útagr,   rP   s      €r.   ú	<genexpr>z'_filter_keys_by_tags.<locals>.<genexpr>l   s>   øè ø€ ò 
àØ#ò
ð ô ×6Ñ6¸SÈ#×NÐNð
ØNñ
ùó   ƒ(+r$   )Ú	key_aliasrB   r;   ÚgetattrÚanyr'   )rO   rP   ÚaffectedÚunnamed_countÚkeyr_   Úkey_tagss    `     r.   Ú_filter_keys_by_tagsrf   _   s…   ø€ ð "$€HØ€MØò #ˆØ—M‘MÒ' Rˆ	Ü*¨3¯<©<¼ÀÀoÐW[Ó9\Ó]ˆÚœó 
àô
õ 
ñ
 Ø—‘ 	Õ*à Ñ"‘ð#ð �]Ð"Ð"r0   Úteamsc                 óÎ   ‡— g }d}| D ]X  }|j                   xs d}t        |j                  «      }|sŒ+t        ˆfd„|D «       «      sŒ@|r|j	                  |«       ŒT|dz  }ŒZ ||fS )zvFilter pre-fetched team rows whose metadata.tags match any patterns.

    Returns (named_aliases, unnamed_count).
    r   rR   c              3   óZ   •K  — | ]"  }‰D ]  }t        j                  ||¬ «      –— Œ Œ$ y­wrU   rX   rZ   s      €r.   r]   z(_filter_teams_by_tags.<locals>.<genexpr>…   s>   øè ø€ ò 
àØ#ò
ð ô ×6Ñ6¸SÈ#×NÐNð
ØNñ
ùr^   r$   )Ú
team_aliasrB   r;   ra   r'   )rg   rP   rb   rc   Úteamrj   Ú	team_tagss    `     r.   Ú_filter_teams_by_tagsrm   x   sy   ø€ ð "$€HØ€MØò #ˆØ—_‘_Ò*¨ˆ
Ü+¨D¯M©MÓ:ˆ	Úœó 
à ô
õ 
ñ
 Ø—‘ 
Õ+à Ñ"‘ð#ð �]Ð"Ð"r0   Ú	all_teamsÚteam_patternsÚexisting_teamsÚexisting_keysc              ƒ   óÜ  ‡K  — g }g }|D ]d  }|j                   xs dŠ‰sŒt        ˆfd„|D «       «      sŒ+‰|vsŒ0|j                  ‰«       |j                  t        |j                  «      «       Œf g }d}	|rnt        | «      j                  j                  dd|iiddit        ¬«      ƒ d	{  –—† }
|
D ]0  }|j                  xs d}|r||vsŒ|j                  |«       Œ,|	d
z  }	Œ2 |||	fS 7 Œ>­w)zFilter pre-fetched teams by alias patterns, then fetch their keys.

    Returns (new_teams, new_keys, unnamed_keys_count).
    rR   c              3   óL   •K  — | ]  }t        j                  ‰|¬ «      –— Œ y­wrU   rX   )r[   r,   rj   s     €r.   r]   z2_find_affected_by_team_patterns.<locals>.<genexpr>¢   s'   øè ø€ ò 
ØZ]ŒK×6Ñ6¸ZÐQT×UÐUñ
ùó   ƒ!$r   Úteam_idr"   rE   rF   rG   Nr$   )
rj   ra   r'   r4   ru   r   rK   rL   r   r_   )rC   rn   ro   rp   rq   Ú	new_teamsÚmatched_team_idsrk   Únew_keysÚunnamed_keys_countrO   rd   r_   rj   s                @r.   Ú_find_affected_by_team_patternsrz   ‘   s  øè ø€ ð #%€IØ)+Ðàò ;ˆØ—_‘_Ò*¨ˆ
Úœ#ó 
Øanô
õ 
ð  Ò/Ø× Ñ  Ô,Ø ×'Ñ'¬¨D¯L©LÓ(9Õ:ð;ð "$€HØÐÙÜ7¸ÓF×LÑL×VÑVØ˜tÐ%5Ð6Ð7Ø Ð(Ü0ð Wó 
÷ 
ˆð
 ò 	(ˆCØŸ™Ò+¨ˆIÙØ MÒ1Ø—O‘O IÕ.à" aÑ'Ñ"ð	(ð �hÐ 2Ð2Ð2ð
ús'   ƒC, C,µC,ºA1C,Â+C*Â,C,ÃC,Úkey_patternsc              ƒ   ó   ‡K  — g }t        | «      j                  j                  t        d|«      ddit        ¬«      ƒ d{  –—† }|D ]@  }|j
                  xs dŠ‰sŒt        ˆfd„|D «       «      sŒ+‰|vsŒ0|j                  ‰«       ŒB |S 7 ŒK­w)z1Find keys whose alias matches the given patterns.r_   rE   rF   rG   NrR   c              3   óL   •K  — | ]  }t        j                  ‰|¬ «      –— Œ y­wrU   rX   )r[   r,   r_   s     €r.   r]   z/_find_affected_keys_by_alias.<locals>.<genexpr>Ê   s'   øè ø€ ò 
ØY\ŒK×6Ñ6¸YÐPS×TÐTñ
ùrt   )r   rK   rL   r/   r   r_   ra   r'   )rC   r{   rq   rb   rO   rd   r_   s         @r.   Ú_find_affected_keys_by_aliasr~   ¼   s¡   øè ø€ ð
 "$€Hä3°MÓB×HÑH×RÑRÜ  ¨lÓ;Ø˜VÐ$Ü,ð Só ÷ €Dð
 ò +ˆØ—M‘MÒ' Rˆ	Úœó 
Ø`lô
õ 
ð  Ò-Ø—‘ 	Õ*ð+ð €Oðús#   ƒ=BÁ BÁBÁBÁ2BÁ7Bz/policies/resolveÚPolicies)r>   ÚdependenciesÚresponse_modelFz?Force a DB sync before resolving. Default uses in-memory cache.)ÚdefaultÚdescriptionÚrequestÚ
force_syncÚuser_api_key_dictc              ƒ   ó¾  K  — ddl m} ddlm} ddlm} |€t        dd¬«      ‚	 |rBt        «       j                  |«      ƒ d{  –—†  t        «       j                  |«      ƒ d{  –—†  t        | j                  | j                  | j                  | j                  ¬	«      }t        «       j!                  |¬
«      }|st#        g g ¬«      S |D �cg c]  }|d   ‘Œ	 }	}|j%                  |	|¬«      }
g }t'        «       }|D ]w  }|d   }||
vrŒ|j)                  |t        «       j+                  «       |¬«      }|r|j,                  ng }|j/                  |«       |j1                  t3        ||d   |¬«      «       Œy t#        t5        |«      |¬«      S 7 �ŒI7 �Œ+c c}w # t        $ r ‚ t6        $ r1}t9        j:                  d|«       t        dt=        |«      ¬«      ‚d}~ww xY w­w)aæ  
    Resolve which policies and guardrails apply for a given context.

    Use this endpoint to debug "what guardrails would apply to a request
    with this team/key/model/tags combination?"

    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/policies/resolve" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "tags": ["healthcare"],
            "model": "gpt-4"
        }'
    ```
    r   )ÚPolicyMatcher)ÚPolicyResolverrM   Néô  úDatabase not connected©Ústatus_codeÚdetail)rj   r_   Úmodelr>   )Úcontext)Úeffective_guardrailsÚmatched_policiesÚpolicy_name)Úpolicy_namesr�   )r“   Úpoliciesr�   Úmatched_via)r“   r–   Úguardrails_addedzError resolving policies: %s)Ú*litellm.proxy.policy_engine.policy_matcherrˆ   Ú+litellm.proxy.policy_engine.policy_resolverr‰   Úlitellm.proxy.proxy_serverrC   r   r   Úsync_policies_from_dbr   Úsync_attachments_from_dbr   rj   r_   r�   r>   Ú"get_attached_policies_with_reasonsr   Ú%get_policies_with_matching_conditionsÚsetÚresolve_policy_guardrailsÚget_all_policiesÚ
guardrailsÚupdater'   r   ÚsortedÚ	Exceptionr
   Ú	exceptionr4   )r„   r…   r†   rˆ   r‰   rC   r�   Úmatch_resultsÚrr”   Úapplied_policy_namesr’   Úall_guardrailsÚresultÚpnameÚresolvedr¢   Úes                     r.   Úresolve_policies_for_contextr¯   ×   sû  è ø€ õ> IÝJÝ8àÐÜ¨Ð4LÔMÐMð<<áÜ%Ó'×=Ñ=¸mÓL×LÐLÜ)Ó+×DÑDÀ]ÓS×SÐSô ,Ø×)Ñ)Ø×'Ñ'Ø—-‘-Ø—‘ô	
ˆô  7Ó8×[Ñ[ÐdkÐ[ÓlˆáÜ(Ø%'Ø!#ôð ð :GÖG°A˜q Ó/ÐGˆÐGØ&3×&YÑ&YØ%Øð 'Zó '
Ðð #%ÐÜ%(£UˆØ#ò 	ˆFØ˜=Ñ)ˆEØÐ0Ñ0ØØ%×?Ñ?Ø!Ü,Ó.×?Ñ?ÓAØð @ó ˆHñ
 19˜×,Ò,¸bˆJØ×!Ñ! *Ô-Ø×#Ñ#Ü!Ø %Ø & }Ñ 5Ø%/ôõð	ô& %Ü!'¨Ó!7Ø-ô
ð 	
ðc MùØSûò( Høô@ ò ØÜò <Ü×&Ñ&Ð'EÀqÔIÜ¨´C¸³FÔ;Ð;ûð<üsl   ‚"G¥F ÁFÁ F Á$FÁ%A#F ÃGÃ	F ÃFÃB2F ÆGÆF ÆF ÆF ÆGÆ),GÇGÇGz%/policies/attachments/estimate-impactc           
   ƒ   ó–  K  — ddl m} |€t        dd¬«      ‚	 | j                  dk(  rt	        ddd	gd
g¬«      S g }g }d}d}| j
                  xs g }| j                  xs g }g }	|s|rt        |«      ƒ d{  –—† }	|rSt        |«      j                  j                  i ddit        ¬«      ƒ d{  –—† }
t        |
|«      \  }}t        |	|«      \  }}|rBt        ||	|||«      ƒ d{  –—† \  }}}|j                  |«       |j                  |«       ||z  }| j                   xs g }|r&t#        |||«      ƒ d{  –—† }|j                  |«       t	        t%        |«      |z   t%        |«      |z   |||dd |dd ¬«      S 7 �Œ7 ŒÐ7 Œ›7 ŒK# t        $ r ‚ t&        $ r1}t)        j*                  d|«       t        dt-        |«      ¬«      ‚d}~ww xY w­w)að  
    Estimate how many keys and teams would be affected by a policy attachment.

    Use this before creating an attachment to preview the blast radius.

    Example Request:
    ```bash
    curl -X POST "http://localhost:4000/policies/attachments/estimate-impact" \
        -H "Authorization: Bearer <your_api_key>" \
        -H "Content-Type: application/json" \
        -d '{
            "policy_name": "hipaa-compliance",
            "tags": ["healthcare", "health-*"]
        }'
    ```
    r   rM   NrŠ   r‹   rŒ   r   r!   u#   (global scope â€” affects all keys)u$   (global scope â€” affects all teams))Úaffected_keys_countÚaffected_teams_countÚsample_keysÚsample_teamsrE   rF   rG   é
   )r±   r²   ry   Úunnamed_teams_countr³   r´   z&Error estimating attachment impact: %s)rš   rC   r   Úscoper   r>   rg   rN   r   rK   rL   r   rf   rm   rz   r(   rO   r~   r)   r¥   r
   r¦   r4   )r„   r†   rC   Úaffected_keysÚaffected_teamsÚunnamed_keysÚunnamed_teamsrP   ro   rn   rO   rv   rx   Únew_unnamedr{   r®   s                   r.   Úestimate_attachment_impactr½   A  s#  è ø€ õ4 9àÐÜ¨Ð4LÔMÐMðG<à�=‰=˜CÒÜ+Ø$&Ø%'ØBÐCØDÐEô	ð ð $&ˆØ$&ˆØˆØˆà%Ÿl™lÒ0¨bˆØ&Ÿ}™}Ò2°ˆð @Bˆ	Ù™=Ü.¨}Ó=×=ˆIñ Ü ;¸MÓ J× PÑ P× ZÑ ZØØ# VÐ,Ü4ð ![ó !÷ ˆDô
 +?¸tÀ\Ó*RÑ'ˆM˜<Ü,AØØó-Ñ)ˆN˜Mñ Ü5TØØØØØó6÷ 0Ñ,ˆI�x ð ×!Ñ! )Ô,Ø× Ñ  Ô*Ø˜KÑ'ˆLð &Ÿl™lÒ0¨bˆÙÜ9ØØØó÷ ˆHð
 × Ñ  Ô*ä'Ü # MÓ 2°\Ñ AÜ!$ ^Ó!4°}Ñ!DØ+Ø -Ø% c rÐ*Ø'¨¨Ð,ô
ð 	
ðM >ùðøð0øðùô ò ØÜò <Ü×&Ñ&Ð'OÐQRÔSÜ¨´C¸³FÔ;Ð;ûð<üs|   ‚G	™F ¸G	¹<F Á5E:Á66F Â,E=Â-6F Ã#E?Ã$AF Ä5FÄ6AF Å9G	Å:F Å=F Å?F ÆF ÆGÆ,GÇGÇG	)N)<Ú__doc__r5   Úcollections.abcr   Útypingr   r   Úfastapir   r   r   r	   Úlitellm._loggingr
   Úlitellm.constantsr   Úlitellm.proxy._typesr   Úlitellm.proxy.auth.route_checksr   Ú$litellm.proxy.auth.user_api_key_authr   Ú/litellm.proxy.policy_engine.attachment_registryr   Ú+litellm.proxy.policy_engine.policy_registryr   Ú$litellm.repositories.team_repositoryr   Ú2litellm.repositories.verification_token_repositoryr   Ú!litellm.types.proxy.policy_enginer   r   r   r   r   r   Úprismar   Úprisma_modelsr   Ú__annotations__r4   r9   Úobjectr/   r:   ÚlistrB   rN   ÚtupleÚintrf   rm   rz   r~   ÚpostÚboolr¯   r½   © r0   r.   ú<module>rÖ      sz  ðòó Ý $ß 'ç <Ó <å 1Ý =Ý /Ý 7Ý BÝ SÝ KÝ ?õ÷÷ ñ Ý.á“€ˆÓ ð˜cð ¨X°c©]ð ¸tÀCÈÀKÑ?Pó ð6	B &ð 	B¨Tó 	Bñ( fð (¸Vð (Ètó (ð¨&ð Ð5`ó ð#Ø
=ð#ØMUÐVYÉ]ð#à
ˆ4�‰9�cˆ>Ñó#ð2#Ø6ð#ØFNÈsÁmð#à
ˆ4�‰9�cˆ>Ñó#ð2(3Øð(3à:ð(3ð ˜C‘=ð(3ð ˜S‘Mð	(3ð
 ˜C‘=ð(3ð ˆ4�‰9�d˜3‘i Ð$Ñ%ó(3ðVØðØ)1°#©ðØGOÐPSÁ}ðà	ˆ#�Yóð6 ‡�ØØ
ˆÙÐ+Ó,Ð-Ø(ð	 ó ñ ØØUôñ )0Ð0AÓ(Bñ\<Ø!ð\<àð\<ð &ò\<óð\<ðH ‡�Ø+Ø
ˆÙÐ+Ó,Ð-Ø+ð	 ó ñ )0Ð0AÓ(Bñ`<Ø*ð`<à%ò`<óñ`<r0   