Ë
    tPêjÆ"  ã                   óÌ   — d Z ddlmZ ddlmZmZ ddlmZmZ ddlm	Z	 ddl
mZmZmZ ddlmZ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 erddlmZ  G d„ d«      Z y)z™
Key Rotation Manager - Automated key rotation based on rotation schedules

Handles finding keys that need rotation based on their individual schedules.
é    )ÚSequence)ÚdatetimeÚtimezone)ÚTYPE_CHECKINGÚFinal)Úverbose_proxy_logger)Ú*LITELLM_INTERNAL_JOBS_SERVICE_ACCOUNT_NAMEÚ!LITELLM_KEY_ROTATION_GRACE_PERIODÚ%LITELLM_KEY_ROTATION_LOCK_TTL_SECONDS)ÚGenerateKeyResponseÚLiteLLM_VerificationTokenÚRegenerateKeyRequest)ÚKeyManagementEventHooks)Ú_calculate_key_rotation_timeÚregenerate_key_fn)ÚPrismaClient)Ú%DeprecatedVerificationTokenRepository)ÚVerificationTokenRepository)Úmodelsc                   óP   — e Zd ZdZddefd„Zd„ Zdd„Zdd„Zd	e	d
e
defd„Zdd„Zy)ÚKeyRotationManagerzT
    Manages automated key rotation based on individual key rotation schedules.
    NÚprisma_clientc                 ó    — || _         || _        y ©N)r   Úpod_lock_manager)Úselfr   r   s      út/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/common_utils/key_rotation_manager.pyÚ__init__zKeyRotationManager.__init__,   s   € Ø*ˆÔØ 0ˆÕó    c              ƒ   ód  K  — ddl m} d}	 | j                  r³| j                  j                  r�t	        t
        d«      }| j                  j                  ||¬«      ƒ d{  –—† xs d}|sbt        j                  d«       	 |rI| j                  r<| j                  j                  r%| j                  j                  |¬«      ƒ d{  –—†  yyyyt        j                  d	«       | j                  «       ƒ d{  –—†  | j                  «       ƒ d{  –—† }|sbt        j                  d
«       	 |rI| j                  r<| j                  j                  r%| j                  j                  |¬«      ƒ d{  –—†  yyyyt        j                  dt        |«      «       |D ]`  }	 | j                  |«      ƒ d{  –—†  |j                   xs  |j"                  r|j"                  dd dz   nd}t        j                  d|«       Œb 	 |rI| j                  r<| j                  j                  r%| j                  j                  |¬«      ƒ d{  –—†  yyyy7 �Œç7 �Œ†7 �ŒX7 �ŒC7 Œå7 Œ¥# t$        $ rP}|j                   xs  |j"                  r|j"                  dd dz   nd}t        j&                  d||«       Y d}~�Œd}~ww xY w# t$        $ r }t        j&                  d|«       Y d}~ŒÜd}~ww xY w7 Œ # |rJ| j                  r=| j                  j                  r&| j                  j                  |¬«      ƒ d{  –—†7   w w w w xY w­w)z¯
        Main entry point - find and rotate keys that are due for rotation.
        Uses PodLockManager to ensure only one pod runs rotation in multi-pod deployments.
        r   )ÚKEY_ROTATION_JOB_NAMEFi,  )Ú
cronjob_idÚttlNu—   Key rotation: another pod is already running rotation or Redis lock acquisition failed â€” skipping this cycle. Keys will be rotated on the next cycle.)r"   z(Starting scheduled key rotation check...z)No keys are due for rotation at this timezFound %s keys due for rotationé   z...ÚunknownzSuccessfully rotated key: %szFailed to rotate key %s: %szKey rotation process failed: %s)Úlitellm.constantsr!   r   Úredis_cacheÚmaxr   Úacquire_lockr   ÚwarningÚrelease_lockÚinfoÚ _cleanup_expired_deprecated_keysÚ_find_keys_needing_rotationÚdebugÚlenÚ_rotate_keyÚkey_nameÚtokenÚ	ExceptionÚerror)r   r!   Úlock_acquiredÚlock_ttlÚkeys_to_rotateÚkeyÚkey_identifierÚes           r   Úprocess_rotationsz$KeyRotationManager.process_rotations0   s-  è ø€ õ
 	<àˆð7	à×$Ò$¨×)>Ñ)>×)JÒ)Jô #&Ü9¸3ó#�ð ×/Ñ/×<Ñ<Ø#8Ø$ð =ó ÷ ò ð ð ñ %Ü(×0Ñ0ðBôð
 ñ<  ×!6Ò!6¸4×;PÑ;P×;\Ò;\Ø×+Ñ+×8Ñ8Ø4ð 9ó ÷ ñ ð <]Ð!6ˆ}ô9 !×%Ñ%Ð&PÔQð ×7Ñ7Ó9×9Ð9ð +/×*JÑ*JÓ*L×$LˆNá!Ü$×*Ñ*Ð+VÔWØñ$  ×!6Ò!6¸4×;PÑ;P×;\Ò;\Ø×+Ñ+×8Ñ8Ø4ð 9ó ÷ ñ ð <]Ð!6ˆ}ô! !×%Ñ%Ð&FÌÈNÓH[Ô\ð &ò a�ðaØ×*Ñ*¨3Ó/×/Ð/Ø%(§\¡\Ò%hÈsÏyÊy°c·i±iÀÀ°mÀeÒ6KÐ^g�NÜ(×-Ñ-Ð.LÈnÕ]ñ	añ  ×!6Ò!6¸4×;PÑ;P×;\Ò;\Ø×+Ñ+×8Ñ8Ø4ð 9ó ÷ ñ ð <]Ð!6ˆ}ðUùðVùð5 :ùð %Mùð.øð 0ùô !ò aØ%(§\¡\Ò%hÈsÏyÊy°c·i±iÀÀ°mÀeÒ6KÐ^g�NÜ(×.Ñ.Ð/LÈnÐ^_×`Ò`ûðaûô ò 	MÜ ×&Ñ&Ð'HÈ!×LÑLûð	Múð
ùñ  ×!6Ò!6¸4×;PÑ;P×;\Ò;\Ø×+Ñ+×8Ñ8Ø4ð 9ó ÷ ò ð <]Ð!6ˆ}üs  ‚	L0ŒAJ1 ÁIÁJ1 Á?AL0ÃIÃL0Ã(J1 Ã3IÃ4J1 ÄIÄJ1 Ä(AL0Å+IÅ,L0Å4$J1 ÆIÆ-IÆ.AIÇ6J1 Ç8K Ç9AL0È<KÈ=L0ÉJ1 ÉL0ÉJ1 ÉJ1 ÉL0ÉIÉ	J.ÉAJ)Ê#J1 Ê)J.Ê.J1 Ê1	KÊ:KËK ËKËK ËL0ËAL-Ì#L&Ì$	L-Ì-L0Úreturnc              ƒ   óÜ   K  — t        j                  t        j                  «      }t	        | j
                  «      j                  j                  dddidd|iigdœ¬«      ƒ d{  –—† }|S 7 Œ­w)zæ
        Find keys that are due for rotation based on their key_rotation_at timestamp.

        Logic:
        - Key has auto_rotate = true
        - key_rotation_at is null (needs initial setup) OR key_rotation_at <= now
        TÚkey_rotation_atNÚlte)Úauto_rotateÚOR©Úwhere)r   Únowr   Úutcr   r   ÚtableÚ	find_many)r   rE   Úkeys_with_rotations      r   r.   z.KeyRotationManager._find_keys_needing_rotationq   su   è ø€ ô —\‘\¤(§,¡,Ó/ˆä*EÀd×FXÑFXÓ*Y×*_Ñ*_×*iÑ*ià#à&¨Ð-Ø&¨°¨Ð5ðñð +jó +
÷ %
Ðð "Ð!ð%
ús   ‚A!A,Á#A*Á$A,c              ƒ   ó^  K  — 	 t        j                  t        j                  «      }t	        | j
                  «      j                  j                  dd|ii¬«      ƒ d{  –—† }|dkD  rt        j                  d|«       yy7 Œ!# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w­w)zK
        Remove deprecated key entries whose revoke_at has passed.
        Ú	revoke_atÚltrC   Nr   z'Cleaned up %s expired deprecated key(s)z8Deprecated key cleanup skipped (table may not exist): %s)r   rE   r   rF   r   r   rG   Údelete_manyr   r/   r4   )r   rE   Úresultr;   s       r   r-   z3KeyRotationManager._cleanup_expired_deprecated_keys‡   s£   è ø€ ð	fÜ!Ÿ™¤h§l¡lÓ3ˆCÜ"GÈ×HZÑHZÓ"[×"aÑ"a×"mÑ"mØ" T¨3 KÐ0ð #nó #÷ ˆFð ˜ŠzÜ$×*Ñ*Ð+TÐV\Õ]ð ðùô
 ò 	fÜ ×&Ñ&Ð'aÐcd×eÑeûð	füsA   ‚B-„AB ÁA?ÁB Á=B-Á?B Â	B*Â
B%Â B-Â%B*Â*B-r9   rE   c                 óT   — |j                   sy|j                  €y||j                  k\  S )zZ
        Determine if a key should be rotated based on key_rotation_at timestamp.
        FT)Úrotation_intervalr?   )r   r9   rE   s      r   Ú_should_rotate_keyz%KeyRotationManager._should_rotate_key•   s4   € ð ×$Ò$Øð ×ÑÐ&Øð �c×)Ñ)Ñ)Ð)r   c              ƒ   ó´  K  — t        |j                  xs d|j                  t        xs d¬«      }ddlm} |j                  «       }t        ||t        ¬«      ƒ d{  –—† }t        |t        «      r©|j                  r�|j                  r‘t        j                  t        j                   «      }t#        |j                  «      }t%        | j&                  «      j(                  j+                  d|j                  i|j,                  xs ddz   ||d	œ¬
«      ƒ d{  –—†  t        |t        «      r't/        j0                  ||||t        ¬«      ƒ d{  –—†  yy7 Œõ7 Œ>7 Œ
­w)za
        Rotate a single key using existing regenerate_key_fn and call the rotation hook
        Ú N)r9   Ú	key_aliasÚgrace_periodr   )ÚUserAPIKeyAuth)ÚdataÚuser_api_key_dictÚlitellm_changed_byr3   é   )Úrotation_countÚlast_rotation_atr?   )rD   rW   )rW   Úexisting_key_rowÚresponserX   rY   )r   r3   rT   r
   Úlitellm.proxy._typesrV   Ú+get_litellm_internal_jobs_user_api_key_authr   r	   Ú
isinstancer   Útoken_idrP   r   rE   r   rF   r   r   r   rG   Úupdater[   r   Úasync_key_rotated_hook)r   r9   Úregenerate_requestrV   Úsystem_userr^   rE   Únext_rotation_times           r   r1   zKeyRotationManager._rotate_key£   s?  è ø€ ô
 %9Ø—	‘	’˜RØ—m‘mÜ:ÒB¸dô%
Ðõ 	8à+×WÑWÓYˆô !2Ø#Ø)ÜIô!
÷ 
ˆô �hÔ 3Ô4¸×9JÒ9JÈs×OdÒOdä!Ÿ™¤h§l¡lÓ3ˆCÜ(DÀS×EZÑEZÓ([ÐÜ-¨d×.@Ñ.@ÓA×GÑG×NÑNØ × 1Ñ 1Ð2à'*×'9Ñ'9Ò'>¸QÀ!Ñ&CØ(+Ø'9ñð Oó ÷ ð ô �hÔ 3Ô4Ü)×@Ñ@Ø'Ø!$Ø!Ø"-Ü#Mô÷ ñ ð 5ð+
øðøðús7   ‚AEÁEÁB8EÄEÄ5EÅEÅEÅEÅEr   )r=   z1Sequence[prisma_models.LiteLLM_VerificationToken])r=   N)r9   z'prisma_models.LiteLLM_VerificationToken)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r<   r.   r-   r   r   ÚboolrQ   r1   © r   r   r   r   '   sE   „ ññ1 ló 1ò?óB"ó,fð*Ð&?ð *Àhð *ÐSWó *ô-r   r   N)!rk   Úcollections.abcr   r   r   Útypingr   r   Úlitellm._loggingr   r&   r	   r
   r   r_   r   r   r   Ú.litellm.proxy.hooks.key_management_event_hooksr   Ú;litellm.proxy.management_endpoints.key_management_endpointsr   r   Úlitellm.proxy.utilsr   Ú'litellm.repositories.table_repositoriesr   Ú2litellm.repositories.verification_token_repositoryr   Úprismar   Úprisma_modelsr   rm   r   r   ú<module>rx      sZ   ðñõ %ß 'ß 'å 1÷ñ ÷
ñ õ
 S÷õ -õõñ Ý.÷iò ir   