
    hI                        d dl Z d dlmZmZmZmZ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mZ d dl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 d dl m!Z" erd dl#m$Z$  G d de%      Z& G d de%      Z' G d de      Z(y)    N)TYPE_CHECKINGAnyDictLiteralOptionalTupleTypeUnion)HTTPException)	DualCache)verbose_proxy_logger)CustomGuardraillog_guardrail_information)get_llm_provider)get_async_httpx_clienthttpxSpecialProvider)UserAPIKeyAuth)*add_guardrail_to_applied_guardrails_header)GuardrailEventHooks)LLMResponseTypes)version)GuardrailConfigModelc                       e Zd ZdZy)PillarGuardrailMissingSecretsz0Exception raised when Pillar API key is missing.N__name__
__module____qualname____doc__     r/var/www/Befach/backend/env/lib/python3.12/site-packages/litellm/proxy/guardrails/guardrail_hooks/pillar/pillar.pyr   r   )   s    :r!   r   c                       e Zd ZdZy)PillarGuardrailAPIErrorz>Exception raised when there's an error calling the Pillar API.Nr   r    r!   r"   r$   r$   /   s    Hr!   r$   c                       e Zd ZdZddgZdZdZ	 	 	 	 d#dee   dee   dee   d	ee   d
df
 fdZ	e
dedededed   d
eeeeef      f
d       Ze
dededed   d
eeeeef      fd       Ze
dededed
efd       Zded
efdZd
eeef   fdZded
eeef   fdZded
eeef   fdZdeeef   deeef   d
eeef   fdZdeeef   ded
dfdZdeeef   d
dfd Zed
ee d!      fd"       Z! xZ"S )$PillarGuardrailz
    Pillar Security Guardrail for LiteLLM.

    Provides comprehensive AI security scanning for input prompts and output responses
    using the Pillar Security API.
    blockmonitorzhttps://api.pillar.securityNguardrail_nameapi_keyapi_baseon_flagged_actionreturnc                    t        t        j                        | _        |xs t        j
                  j                  d      | _        | j                  d}t        |      |xs# t	        j                  d      xs | j                  | _        |xs t        j
                  j                  d      }|r|| j                  v r|| _        n,|rt        j                  d| d       | j                   | _        t        j"                  d	| j                          t$        j&                  t$        j(                  t$        j*                  g}t-        	| \  d||d
| y)ai  
        Initialize the Pillar guardrail.

        Args:
            guardrail_name: Name of the guardrail instance
            api_key: Pillar API key
            api_base: Pillar API base URL
            on_flagged_action: Action to take when content is flagged ('block' or 'monitor')
            **kwargs: Additional arguments passed to parent class
        )llm_providerPILLAR_API_KEYNCouldn't get Pillar API key, either set the `PILLAR_API_KEY` in the environment or pass it as a parameter to the guardrail in the config filePILLAR_API_BASEPILLAR_ON_FLAGGED_ACTIONzInvalid action 'z', using defaultz6Pillar Guardrail: Initialized with on_flagged_action: )r)   supported_event_hooksr    )r   r   GuardrailCallbackasync_handlerosenvirongetr*   r   getenvBASE_API_URLr+   SUPPORTED_ON_FLAGGED_ACTIONSr,   r   warningDEFAULT_ON_FLAGGED_ACTIONdebugr   pre_callduring_call	post_callsuper__init__)
selfr)   r*   r+   r,   kwargsmsgactionr4   	__class__s
            r"   rD   zPillarGuardrail.__init__B   sB   $ 4-??
 B"**..1A"B<<M  044 UBII.?$@UDDUDU #Pbjjnn5O&Pf A AA%+D"$,,&vh.>? &*%C%CD"""DTE[E[D\]	
  ((++))!
 	 	
)"7	
 	
r!   user_api_key_dictcachedata	call_type)
completiontext_completion
embeddingsimage_generation
moderationaudio_transcriptionpass_through_endpointrerankc                 .  K   t         j                  }| j                  ||      dur$t        j                  d| j
                          |S t        j                  d       | j                  |       d{   }t        || j
                         |S 7 w)a  
        Pre-call hook to scan the request for security threats before sending to LLM.

        Args:
            user_api_key_dict: User API key authentication info
            cache: LiteLLM cache instance
            data: Request data
            call_type: Type of LLM call

        Returns:
            Original data if safe, raises HTTPException if blocked

        Raises:
            HTTPException: If request should be blocked due to security threats
        rL   
event_typeTz1Pillar Guardrail: Pre-call scanning disabled for zPillar Guardrail: Pre-call hookNrequest_datar)   )r   r@   should_run_guardrailr   r?   r)   run_pillar_guardrailr   )rE   rJ   rK   rL   rM   rX   results          r"   async_pre_call_hookz#PillarGuardrail.async_pre_call_hook   s     @ )11
$$$:$FdR &&CDDWDWCXY K""#DE0066 	3d.A.A	
  7   A3B5B6B)rN   rP   rQ   rR   rS   	responsesc                 .  K   t         j                  }| j                  ||      dur$t        j                  d| j
                          |S t        j                  d       | j                  |       d{   }t        || j
                         |S 7 w)a  
        During-call hook to scan the request in parallel with LLM processing.

        Args:
            data: Request data
            user_api_key_dict: User API key authentication info
            call_type: Type of LLM call

        Returns:
            Original data if safe, raises HTTPException if blocked

        Raises:
            HTTPException: If request should be blocked due to security threats
        rW   Tz4Pillar Guardrail: During-call scanning disabled for z-Pillar Guardrail: During-call moderation hookNrY   )r   rA   r[   r   r?   r)   r\   r   )rE   rL   rJ   rM   rX   r]   s         r"   async_moderation_hookz%PillarGuardrail.async_moderation_hook   s     8 )44
$$$:$FdR &&FtGZGZF[\ K""#RS0066 	3d.A.A	
  7r_   responsec                 t  K   t         j                  }| j                  ||      dur$t        j                  d| j
                          |S t        j                  d       t        |d      r|j                         ni }|j                  dg       D cg c]$  }|j                  d      r|j                  d      & }}|st        j                  d       |S |j                         }|j                  d	g       |z   |d	<   | j                  |       d
{    t        || j
                         |S c c}w 7 "w)a  
        Post-call hook to scan LLM responses before returning to user.

        Args:
            data: Original request data
            user_api_key_dict: User API key authentication info
            response: LLM response to scan

        Returns:
            Original response if safe, raises HTTPException if blocked

        Raises:
            HTTPException: If response should be blocked due to security threats
        rW   Tz2Pillar Guardrail: Post-call scanning disabled for z Pillar Guardrail: Post-call hook
model_dumpchoicesmessagezJPillar Guardrail: No response content to scan, skipping post-call analysismessagesNrY   )r   rB   r[   r   r?   r)   hasattrre   r9   copyr\   r   )	rE   rL   rJ   rc   rX   response_dictchoiceresponse_messagespost_call_datas	            r"   async_post_call_success_hookz,PillarGuardrail.async_post_call_success_hook   s?    * )22
$$$:$FdR &&DTEXEXDYZ O""#EF 29<1P++-VX (++Ir:
zz)$ JJy!
 
 ! &&\ O %)XXj"%=@Q%Qz" ''777 	3d.A.A	
 1
" 	8s   BD8)D1<AD8D6#D8c                   K   |j                  d      st        j                  d       |S 	 | j                         }| j	                  |      }| j                  ||       d{   }| j                  ||       |S 7 # t        $ rO}t        |t              r|t        j                  dt        |              t        dt        |             d}~ww xY ww)ao  
        Core method to run the Pillar guardrail scan.

        Args:
            data: Request data containing messages and metadata

        Returns:
            Original data if safe or in monitor mode

        Raises:
            PillarGuardrailAPIError: If the Pillar API call fails
            HTTPException: If content is flagged and action is 'block'
        rh   z?Pillar Guardrail: No messages detected, bypassing security scan)headerspayloadNz-Pillar Guardrail: API communication failed - z@Pillar Guardrail scan failed - unable to verify request safety: )r9   r   r?   _prepare_headers_prepare_payload_call_pillar_api_process_pillar_response	Exception
isinstancer   errorstrr$   )rE   rL   rq   rr   rc   es         r"   r\   z$PillarGuardrail.run_pillar_guardrail  s      xx
# &&Q K	++-G++D1G!22 3  H ))(D9K  	!]+ &&?AxH *RSVWXSYRZ[ 	s;   )C7A> #A<$A> ;C<A> >	CA
CCCc                 p    | j                   sd}t        |      d| j                    dd}d|d<   d|d<   |S )z+Prepare headers for the Pillar API request.r1   zBearer zapplication/json)AuthorizationzContent-Typetrueplr_evidenceplr_scanners)r*   r   )rE   rG   rq   s      r"   rs   z PillarGuardrail._prepare_headersN  sV    ||M  044  't||n5.#
 #)"(r!   c                 @   |j                  d      }|sy	 t        ||j                  d      |j                  d      |j                  d            \  }}}}|xs d|xs dfS # t        $ r1 |xs d|j                  d      xs |j                  d      xs dfcY S w xY w)	z
        Extract the model and provider from the request data.

        Args:
            data: Request data

        Returns:
            Tuple of (model_name, provider_name)
        model)unknownr   custom_llm_providerr+   r*   )r   r   r+   r*   r   provider)r9   r   rw   )rE   rL   r   clean_modelr   _s         r"   _extract_model_and_providerz+PillarGuardrail._extract_model_and_providerb  s     !'	*:$(HH-B$C*-+	+'K1a +)X-BBB 	 "./T488J3GT9 	s   AA# #7BBc           
      j   |j                  dg       }|j                  dg       }dt        d}|||d}|j                  d      }|r||d<   |j                  di       j                  d	      }|r||d
<   | j                  |      \  }}	||d<   |	|d<   t        j                  d| d| d| d|	        |S )z
        Prepare the payload for the Pillar API request following the /api/v1/protect contract.

        Args:
            data: Request data

        Returns:
            Formatted payload for Pillar API
        rh   toolslitellm)sourcer   )rh   r   metadatauseruser_idr   pillar_session_id
session_idr   r   z)Pillar Guardrail: Request context - user=
, session=z, model=z, provider=)r9   litellm_versionr   r   r?   )
rE   rL   rh   r   r   rr   r   r   r   r   s
             r"   rt   z PillarGuardrail._prepare_payload  s     88J+"%&
 ! 
 ((6"!(GI XXj"-112EF
$.GL! ::4@x &
""7y
:, WG;xj2	
 r!   rq   rr   c           	        K   t        j                  dt        |j                  dg              d       | j                  j                  | j                   d||d       d{   }|j                          |j                         }|j                  d      }|j                  d	      }t        j                  d
| d|        |S 7 cw)z
        Call the Pillar API and return the response.

        Args:
            headers: HTTP headers for the request
            payload: Request payload

        Returns:
            Pillar API response as dictionary
        zPillar Guardrail: Scanning rh   z messages for security threatsz/api/v1/protectg      >@)urlrq   jsontimeoutNflaggedr   z.Pillar Guardrail: Analysis complete - flagged=r   )	r   r?   lenr9   r6   postr+   raise_for_statusr   )rE   rq   rr   rc   resr   r   s          r"   ru   z PillarGuardrail._call_pillar_api  s      	"")#gkk*b.I*J)KKij	
 ++00==/1	 1 
 
 	!!#mmo'')$WW\*
""<WIZPZ|\	
 

s   A"C
$C%A$C
pillar_responseoriginal_datac                 p   |sy|j                  dd      }|j                  d      }|r0t        j                  d|        d|vri |d<   d|d   vr||d   d<   |r\t        j                  d       | j                  d	k(  r| j                  |       y| j                  d
k(  rt        j                  d       yyy)aS  
        Process the Pillar API response and handle detections based on configuration.

        Args:
            pillar_response: Response from Pillar API
            original_data: Original request data (modified in-place with session info)

        Raises:
            HTTPException: If content is flagged and action is 'block'
        Nr   Fr   z3Pillar Guardrail: Received session_id from server: r   r   z!Pillar Guardrail: Threat detectedr'   r(   zGPillar Guardrail: Monitoring mode - allowing flagged content to proceed)r9   r   r?   r=   r,   !_raise_pillar_detection_exceptioninfo)rE   r   r   r   r   s        r"   rv   z(PillarGuardrail._process_pillar_response  s     !%%i7 ,//= &&EFWEXY .,.j)"-
*CCARj)*=> (()LM%%066G''94$))] 5	 r!   c                     dd|j                  d      |j                  di       |j                  dg       dd}t        j                  d       t        d	|
      )a  
        Raise an HTTPException for Pillar security detections.

        Args:
            pillar_response: Response from Pillar API containing detection details

        Raises:
            HTTPException: Always raises with security detection details
        z$Blocked by Pillar Security GuardrailzSecurity threats detectedr   scannersevidence)r   r   r   )ry   detection_messager   z=Pillar Guardrail: Request blocked - Security threats detectedi  )status_codedetail)r9   r   r=   r   )rE   r   error_details      r"   r   z1PillarGuardrail._raise_pillar_detection_exception  sf     <!<-11,?+//
B?+//
B? 
 	$$K	
 LAAr!   r   c                      ddl m}  | S )z
        Get the configuration model for this guardrail.

        Returns:
            Pydantic model class for guardrail configuration
        r   PillarGuardrailConfigModel)5litellm.types.proxy.guardrails.guardrail_hooks.pillarr   r   s    r"   get_config_modelz PillarGuardrail.get_config_model  s    	
 *)r!   )zpillar-securityNNN)#r   r   r   r   r<   r>   r;   r   rz   rD   r   r   r   dictr   r
   rw   r^   rb   r   ro   r\   r   rs   r   r   r   rt   ru   rv   r   staticmethodr	   r   __classcell__)rI   s   @r"   r&   r&   6   sg    %,Y#7  )0L ):!%"&+/:
 :
 #:
 3-	:

 $C=:
 
:
@ .). . 	.
 	
. 
%	3,-	.. .` ** ** 
	* 
%	3,-	.* *X 77 *7 #	7
 
7 7z*t * *`$sCx. ( sCx <+T +d38n +ZCH~04S#X	c3h@%#CH~%>B%	%NB#CH~B	B@ *ht,B'CD * *r!   r&   ))r7   typingr   r   r   r   r   r   r	   r
   fastapir   r   r   litellm._loggingr   %litellm.integrations.custom_guardrailr   r   1litellm.litellm_core_utils.get_llm_provider_logicr   &litellm.llms.custom_httpx.http_handlerr   r   litellm.proxy._typesr   )litellm.proxy.common_utils.callback_utilsr   litellm.types.guardrailsr   litellm.types.utilsr   litellm._versionr   r   3litellm.types.proxy.guardrails.guardrail_hooks.baser   rw   r   r$   r&   r    r!   r"   <module>r      ss    
 R R R "  1 O 0 9 0 7 X	I 		i 	j*o j*r!   