o
    ưiF                     @   s   U d Z ddlmZmZ ddlmZmZmZmZmZ ddl	m
Z
 ddlmZmZmZmZ er3ddlmZ G dd dZd	aee ed
< defddZd	S )z
Attachment Registry - Manages policy attachments from YAML config.

Attachments define WHERE policies apply, separate from the policy definitions.
This allows the same policy to be attached to multiple scopes.
    )datetimetimezone)TYPE_CHECKINGAnyDictListOptional)verbose_proxy_logger)PolicyAttachmentPolicyAttachmentCreateRequestPolicyAttachmentDBResponsePolicyMatchContext)PrismaClientc                	   @   s  e Zd ZdZdd Zdeeeef  ddfddZ	d	eeef de
fd
dZdedee fddZdedeeeef  fddZede
dedefddZdededefddZdee
 fddZdedee
 fddZdefddZd4ddZde
ddfdd Zdedefd!d"Zd#edefd$d%Z	d5d&ed'd(d)ee defd*d+Zd#ed'd(deeef fd,d-Zd#ed'd(dee fd.d/Z d'd(dee fd0d1Z!	'	(		d6d2d3Z"dS )7AttachmentRegistrya  
    In-memory registry for storing and managing policy attachments.

    Attachments define the relationship between policies and their scopes.
    A single policy can have multiple attachments (applied to different scopes).

    Example YAML:
    ```yaml
    attachments:
      - policy: global-baseline
        scope: "*"
      - policy: healthcare-compliance
        teams: [healthcare-team]
      - policy: dev-safety
        keys: ["dev-key-*"]
    ```
    c                 C   s   g | _ d| _d S )NF_attachments_initializedself r   f/home/app/Keep/.python/lib/python3.10/site-packages/litellm/proxy/policy_engine/attachment_registry.py__init__*   s   
zAttachmentRegistry.__init__attachments_configreturnNc                 C   s   g | _ |D ]8}z| |}| j | td|j  W q ty= } ztdt|  t	dt| |d}~ww d| _
tdt| j  d dS )z
        Load attachments from a configuration list.

        Args:
            attachments_config: List of attachment dictionaries from YAML.
        zLoaded attachment for policy: zError loading attachment: zInvalid attachment: NTzLoaded z policy attachments)r   _parse_attachmentappendr	   debugpolicy	Exceptionerrorstr
ValueErrorr   infolen)r   r   attachment_data
attachmenter   r   r   load_attachments.   s"   

z#AttachmentRegistry.load_attachmentsr$   c              	   C   s:   t |dd|d|d|d|d|ddS )	z
        Parse an attachment from raw configuration data.

        Args:
            attachment_data: Raw attachment configuration

        Returns:
            Parsed PolicyAttachment object
        r    scopeteamskeysmodelstagsr   r)   r*   r+   r,   r-   )r
   get)r   r$   r   r   r   r   G   s   

z$AttachmentRegistry._parse_attachmentcontextc                 C   s   dd |  |D S )z
        Get list of policy names attached to the given context.

        Args:
            context: The request context to match against

        Returns:
            List of policy names that are attached to matching scopes
        c                 S   s   g | ]}|d  qS policy_namer   ).0rr   r   r   
<listcomp>d   s    z<AttachmentRegistry.get_attached_policies.<locals>.<listcomp>)"get_attached_policies_with_reasons)r   r0   r   r   r   get_attached_policiesZ      
z(AttachmentRegistry.get_attached_policiesc                 C   s   ddl m} g }t }| jD ]@}| }|j||drN|j|vrN||j | ||}|	|j|d t
d|j d| d|j d|j d	|j d
 q|S )z
        Get list of policy names and match reasons for the given context.

        Returns a list of dicts with 'policy_name' and 'matched_via' keys.
        The 'matched_via' describes which dimension caused the match.
        r   PolicyMatcher)r)   r0   )r2   matched_viazAttachment matched: policy=z, matched_via=z, context=(team=z, key=z, model=))*litellm.proxy.policy_engine.policy_matcherr:   setr   Zto_policy_scopeZscope_matchesr   add_describe_match_reasonr   r	   r   
team_alias	key_aliasmodel)r   r0   r:   resultsZseen_policiesr%   r)   r;   r   r   r   r6   f   s6   	


z5AttachmentRegistry.get_attached_policies_with_reasonsr%   c                    s   ddl m   rdS g }jr+|jr+ fdd|jD }|r+|d|d   jr:|jr:|d|j  jrI|jrI|d|j  j	rX|j
rX|d	|j
  |r_d
|S dS )z/Describe why an attachment matched the context.r   r9   zscope:*c                    s   g | ]}  |jr|qS r   )Zmatches_patternr-   )r3   tr:   r%   r   r   r5      s    z=AttachmentRegistry._describe_match_reason.<locals>.<listcomp>ztag:zteam:zkey:zmodel:+zscope:default)r=   r:   	is_globalr-   r   r*   rA   r+   rB   r,   rC   join)r%   r0   reasonsZmatching_tagsr   rF   r   r@      s"   z)AttachmentRegistry._describe_match_reasonr2   c                 C   s   |  |}||v S )a  
        Check if a specific policy is attached to the given context.

        Args:
            policy_name: Name of the policy to check
            context: The request context to match against

        Returns:
            True if the policy is attached to a matching scope
        )r7   )r   r2   r0   Zattachedr   r   r   is_policy_attached   s   
z%AttachmentRegistry.is_policy_attachedc                 C   s
   | j  S )zp
        Get all loaded attachments.

        Returns:
            List of all PolicyAttachment objects
        )r   copyr   r   r   r   get_all_attachments   s   
z&AttachmentRegistry.get_all_attachmentsc                    s    fdd| j D S )z
        Get all attachments for a specific policy.

        Args:
            policy_name: Name of the policy

        Returns:
            List of attachments for the policy
        c                    s   g | ]	}|j  kr|qS r   r   r3   ar1   r   r   r5          zAAttachmentRegistry.get_attachments_for_policy.<locals>.<listcomp>)r   )r   r2   r   r1   r   get_attachments_for_policy   r8   z-AttachmentRegistry.get_attachments_for_policyc                 C   s   | j S )z
        Check if the registry has been initialized with attachments.

        Returns:
            True if attachments have been loaded, False otherwise
        )r   r   r   r   r   is_initialized   s   z!AttachmentRegistry.is_initializedc                 C   s   g | _ d| _dS )z:
        Clear all attachments from the registry.
        FNr   r   r   r   r   clear   s   
zAttachmentRegistry.clearc                 C   s"   | j | td|j  dS )zp
        Add a single attachment.

        Args:
            attachment: PolicyAttachment object to add
        zAdded attachment for policy: N)r   r   r	   r   r   )r   r%   r   r   r   add_attachment   s   z!AttachmentRegistry.add_attachmentc                    sP   t | j} fdd| jD | _|t | j }|dkr&td| d   |S )z
        Remove all attachments for a specific policy.

        Args:
            policy_name: Name of the policy

        Returns:
            Number of attachments removed
        c                    s   g | ]	}|j  kr|qS r   rN   rO   r1   r   r   r5      rQ   zDAttachmentRegistry.remove_attachments_for_policy.<locals>.<listcomp>r   zRemoved z attachment(s) for policy: )r#   r   r	   r   )r   r2   Zoriginal_countremoved_countr   r1   r   remove_attachments_for_policy   s   

z0AttachmentRegistry.remove_attachments_for_policyattachment_idc                 C   s   dS )z
        Remove an attachment by its ID (for DB-synced attachments).

        Args:
            attachment_id: The ID of the attachment to remove

        Returns:
            True if removed, False if not found
        Fr   )r   rX   r   r   r   remove_attachment_by_id   s   z*AttachmentRegistry.remove_attachment_by_idattachment_requestprisma_clientr   
created_byc                    s  zd|j jj|j|j|jpg |jpg |jpg |jpg t	
tjt	
tj||d
dI dH }t|j|j|j|j|j|jd}| | t|j|j|j|jpNg |jpRg |jpVg |jpZg |j|j|j|jdW S  ty } ztd|  tdt| d}~ww )aL  
        Add a policy attachment to the database.

        Args:
            attachment_request: The attachment creation request
            prisma_client: The Prisma client instance
            created_by: User who created the attachment

        Returns:
            PolicyAttachmentDBResponse with the created attachment
        )
r2   r)   r*   r+   r,   r-   
created_at
updated_atr\   
updated_by)dataNr.   rX   r2   r)   r*   r+   r,   r-   r]   r^   r\   r_   zError adding attachment to DB: )dblitellm_policyattachmenttablecreater2   r)   r*   r+   r,   r-   r   nowr   utcr
   rU   r   rX   r]   r^   r\   r_   r   r	   	exceptionr    )r   rZ   r[   r\   Zcreated_attachmentr%   r&   r   r   r   add_attachment_to_db  sV   



z'AttachmentRegistry.add_attachment_to_dbc              
      s   z7|j jjd|idI dH }|du rtd| d|j jjd|idI dH  | |I dH  dd| diW S  tyU } ztd	|  td	t| d}~ww )
z
        Delete a policy attachment from the database.

        Args:
            attachment_id: The ID of the attachment to delete
            prisma_client: The Prisma client instance

        Returns:
            Dict with success message
        rX   whereNzAttachment with ID z
 not foundmessagezAttachment z deleted successfullyz#Error deleting attachment from DB: )	rb   rc   find_uniquer   deletesync_attachments_from_dbr	   rg   r    r   rX   r[   r%   r&   r   r   r   delete_attachment_from_dbF  s$   
z,AttachmentRegistry.delete_attachment_from_dbc                    s   z7|j jjd|idI dH }|du rW dS t|j|j|j|jp!g |jp%g |j	p)g |j
p-g |j|j|j|jdW S  tyU } ztd|  tdt| d}~ww )a  
        Get a policy attachment by ID from the database.

        Args:
            attachment_id: The ID of the attachment to retrieve
            prisma_client: The Prisma client instance

        Returns:
            PolicyAttachmentDBResponse if found, None otherwise
        rX   ri   Nra   z"Error getting attachment from DB: )rb   rc   rl   r   rX   r2   r)   r*   r+   r,   r-   r]   r^   r\   r_   r   r	   rg   r    ro   r   r   r   get_attachment_by_id_from_dbn  s4   
z/AttachmentRegistry.get_attachment_by_id_from_dbc              
      sh   z|j jjddidI dH }dd |D W S  ty3 } ztd|  tdt| d}~ww )z
        Get all policy attachments from the database.

        Args:
            prisma_client: The Prisma client instance

        Returns:
            List of PolicyAttachmentDBResponse objects
        r]   Zdesc)orderNc                 S   sP   g | ]$}t |j|j|j|jpg |jpg |jpg |jpg |j|j	|j
|jd qS )ra   )r   rX   r2   r)   r*   r+   r,   r-   r]   r^   r\   r_   rO   r   r   r   r5     s     zBAttachmentRegistry.get_all_attachments_from_db.<locals>.<listcomp>z#Error getting attachments from DB: )rb   rc   Z	find_manyr   r	   rg   r    )r   r[   attachmentsr&   r   r   r   get_all_attachments_from_db  s   
z.AttachmentRegistry.get_all_attachments_from_dbc              
      s   zK|  |I dH }g | _|D ],}t|j|j|jr|jnd|jr#|jnd|jr*|jnd|jr1|jndd}| j	| qd| _
tdt| d W dS  tyi } ztd|  tdt| d}~ww )z
        Sync policy attachments from the database to in-memory registry.

        Args:
            prisma_client: The Prisma client instance
        Nr.   TzSynced z* attachments from DB to in-memory registryz#Error syncing attachments from DB: )rt   r   r
   r2   r)   r*   r+   r,   r-   r   r   r	   r"   r#   r   rg   r    )r   r[   rs   Zattachment_responser%   r&   r   r   r   rn     s.   

z+AttachmentRegistry.sync_attachments_from_db)r   N)N)r[   r   r   N)#__name__
__module____qualname____doc__r   r   r   r    r   r'   r
   r   r   r7   r6   staticmethodr@   boolrK   rM   rR   rS   rT   rU   intrW   rY   r   r   r   rh   rp   rq   rt   rn   r   r   r   r   r      s    
"
	
	

?

(
*
(r   N_attachment_registryr   c                   C   s   t du rt a t S )zs
    Get the global AttachmentRegistry singleton.

    Returns:
        The global AttachmentRegistry instance
    N)r|   r   r   r   r   r   get_attachment_registry  s   r}   )rx   r   r   typingr   r   r   r   r   Zlitellm._loggingr	   Z!litellm.types.proxy.policy_enginer
   r   r   r   Zlitellm.proxy.utilsr   r   r|   __annotations__r}   r   r   r   r   <module>   s       Q