Ë
    tPêj¾*  ã                   óú  — U d Z ddlZddlZddlZddl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mZ ddlmZ ddlmZ dd	lmZ d
Zeed<   dZeed<   dZeed<   e› de› de› de› d�Zeed<   dZeed<    eh d£«      Zeee      ed<    eh d£«      Zeee      ed<   dee z  dz  dede fd„Z!dedefd„Z"dedefd „Z# e	d!d!¬"«       G d#„ d$«      «       Z$d%ede$fd&„Z% e	d!d!¬"«       G d'„ d(«      «       Z& e	d!d!¬"«       G d)„ d*«      «       Z'e&e'z  Z(eed+<   d,e(d-e$defd.„Z)d,e(d/ede
dz  fd0„Z*d/ede
dz  fd1„Z+ G d2„ d3e«      Z,d/ede
dz  fd4„Z-ej\                  deg ef   fd5„«       Z/d6e d7e de(dz  fd8„Z0de(dz  fd9„Z1y):aM  Token-based authentication for the proxy's Postgres connection.

Two managed Postgres offerings hand the client a short-lived credential that is used as
the Postgres password: AWS RDS with IAM auth, and Azure Database for PostgreSQL Flexible
Server with Microsoft Entra ID. Both need the same machinery (mint at startup, read the
expiry back off the token, mint again before it lapses) and differ only in how the token
is produced and how its expiry is encoded, so the difference lives in a tagged union that
is resolved once from the environment and injected into whatever needs a token.
é    N)ÚCallable)Ú	dataclass)ÚdatetimeÚ	timedeltaÚtimezone)ÚFinalÚ	TypeAlias)Ú	BaseModel)Úassert_never)Úverbose_proxy_loggerÚIAM_TOKEN_DB_AUTHÚIAM_TOKEN_DB_AUTH_ENV_VARÚAZURE_POSTGRESQL_AUTHÚAZURE_POSTGRESQL_AUTH_ENV_VARz2https://ossrdbms-aad.database.windows.net/.defaultÚAZURE_POSTGRESQL_SCOPEz and zW are both enabled, but the database password can only come from one token source. Keep z for AWS RDS IAM auth, or zT for Azure Database for PostgreSQL with Microsoft Entra ID, and unset the other one.ÚCONFLICTING_TOKEN_AUTH_MESSAGEÚ5432ÚDEFAULT_POSTGRES_PORT>   Ú1ÚtÚyÚonÚyesÚtrueÚTRUTHY_TOKEN_AUTH_VALUES>   Ú Ú0ÚfÚnÚnoÚoffÚfalseÚFALSY_TOKEN_AUTH_VALUESÚvalueÚenv_varÚreturnc                ó8  — t        | t        «      r| S | €y| j                  «       j                  «       }|t        v ry|t
        v ryt        |› d| ›ddj                  t        t        «      «      › ddj                  t        d„ t
        D «       «      «      › d�«      ‚)	aˆ  Whether a token-auth toggle is on, rejecting anything it cannot read.

    The single parser for both toggles. Every entry point (the settings model, the
    CLI, and the refresh loop's own env lookup) routes through this, so a value like
    ``"1"`` cannot enable minting in one place and leave the refresh loop convinced
    token auth is off, which would strand a pod on a token it never renews.

    A value that is neither recognizably on nor recognizably off raises: silently
    reading a typo as off would downgrade an operator from token auth to password
    auth, and the first sign of it would be a connection refused by the server.
    FTú=z/ is not a recognized boolean. Set it to one of z, z to turn it on, or to one of c              3   ó&   K  — | ]	  }|sŒ|–— Œ y ­w©N© )Ú.0Úvs     ú`/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/proxy/db/token_auth.pyú	<genexpr>z*token_auth_flag_enabled.<locals>.<genexpr>B   s   è ø€ ÒD !Â!œAÑDùs   ‚Šz to turn it off.)	Ú
isinstanceÚboolÚstripÚlowerr   r#   Ú
ValueErrorÚjoinÚsorted)r$   r%   Ú
normalizeds      r.   Útoken_auth_flag_enabledr8   *   sž   € ô �%œÔØˆØ€}ØØŸ™›×+Ñ+Ó-€JØÔ-Ñ-ØØÔ,Ñ,ØÜ
Øˆ)�1�U�IÐLØ�9‰9”VÔ4Ó5Ó6Ð
7Ð7TØ�9‰9”VÑDÔ'>ÔDÓDÓEÐ
FÐFVð	Xóð ó    c                 óD   — t         j                  j                  | d¬«      S )Nr   ©Úsafe)ÚurllibÚparseÚquote©r$   s    r.   Ú_quoterA   F   s   € Ü�<‰<×Ñ˜e¨"ÐÓ-Ð-r9   c                 ó~   — t         j                  j                  t         j                  j                  | «      d¬«      S )aš  Percent-encode a URL component that may already be percent-encoded.

    ``DATABASE_USER`` used to be interpolated raw, so pre-encoding was the only way to
    put an ``@`` in it. Encoding such a value again would double-escape it, so decode
    first: the round trip is idempotent and leaves an already-encoded value byte for
    byte as it was, while a raw UPN like ``svc@corp`` still comes out encoded.
    r   r;   )r=   r>   r?   Úunquoter@   s    r.   Ú_normalize_quoterD   J   s-   € ô �<‰<×ÑœfŸl™l×2Ñ2°5Ó9ÀÐÓCÐCr9   T)ÚfrozenÚslotsc                   ó^   — e Zd ZU dZeed<   eed<   eed<   eed<   dZedz  ed<   ded	efd
„Zy)ÚIAMEndpointaF  Static parts of a token-authenticated Postgres connection.

    The token rotates every few minutes to an hour depending on the provider;
    everything else (host, port, user, database name, schema) stays fixed. Capturing
    the static fields once means a refresh only regenerates the token and reassembles
    the URL.
    ÚhostÚportÚuserÚnameNÚschemaÚtokenr&   c                 óè   — dt        | j                  «      › d|› d| j                  › d| j                  › dt        | j                  «      › �
}| j
                  s|S |› dt        | j
                  «      › �S )aÖ  Assemble the connection URL, inserting ``token`` verbatim as the password.

        User, database name, and schema are normalized rather than encoded outright,
        because an Entra principal is a UPN containing ``@`` while an operator on the
        older RDS path may already have encoded that ``@`` themselves. The token is
        left alone: both providers hand it back already in wire form, and re-encoding
        it would double-escape the password.
        zpostgresql://ú:ú@ú/z?schema=)rD   rK   rI   rJ   rL   rM   )ÚselfrN   Úbases      r.   Ú	build_urlzIAMEndpoint.build_urle   sw   € ð Ô,¨T¯Y©YÓ7Ð8¸¸%¸ÀÀ$Ç)Á)ÀÈAÈdÏiÉiÈ[ÐXYÔZjÐko×ktÑktÓZuÐYvÐwð 	ð �{Š{ØˆKØ��xÔ 0°·±Ó =Ð>Ð?Ð?r9   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__rM   rU   r+   r9   r.   rH   rH   U   sA   … ñð ƒIØ
ƒIØ
ƒIØ
ƒIØ€FˆC�$‰JÓð@˜sð @ sô @r9   rH   Úurlc                 óŒ  — t         j                  j                  | «      }|j                  r|j                  st        d«      ‚t         j                  j                  |j                  xs dj                  d«      «      }|st        d«      ‚|j                  rt        |j                  «      nt        }|j                  r8t         j                  j                  |j                  «      j                  d«      nd}t        |j                  |t         j                  j                  |j                  «      ||r
|d   ¬«      S d¬«      S )zÖParse an :class:`IAMEndpoint` back out of a Postgres URL.

    Used so a reader URL can drive its own token refresh without requiring callers to
    set parallel ``DATABASE_HOST_READ_REPLICA`` / etc. env vars.
    z<Cannot parse IAM endpoint from URL: missing host or usernamerR   z9Cannot parse IAM endpoint from URL: missing database namerM   Nr   )rI   rJ   rK   rL   rM   )r=   r>   ÚurlparseÚhostnameÚusernamer4   rC   ÚpathÚlstriprJ   rZ   r   ÚqueryÚparse_qsÚgetrH   )r\   ÚparsedrL   rJ   Úschema_valuess        r.   Úparse_iam_endpoint_from_urlrh   v   sö   € ô —L‘L×)Ñ)¨#Ó.€FØ�?Š? &§/¢/ÜÐWÓXÐXÜ—,‘,×&Ñ&¨¯©Ò(:°s×'BÑ'BÀ3Ó'GÓH€DÙÜÐTÓUÐUØ&,§k¢k”#�f—k‘kÔ"Ô7L€DØPV×P\ÒP\œ6Ÿ<™<×0Ñ0°·±Ó>×BÑBÀ8ÔLÐbf€MÜØ�_‰_ØÜ�\‰\×!Ñ! &§/¡/Ó2ØÙ#0ˆ}˜QÑôð ð
 7;ôð r9   c                   ó<   — e Zd ZdZedefd„«       Zedefd„«       Zy)ÚRdsIamTokenAuthzRAWS RDS IAM auth: a SigV4-presigned token minted from the ambient AWS credentials.r&   c                  ó   — y)NzRDS IAM tokenr+   ©rS   s    r.   ÚlabelzRdsIamTokenAuth.label‘   s   € àr9   c                 ó   — t         S r*   )r   rl   s    r.   r%   zRdsIamTokenAuth.env_var•   s   € ä(Ð(r9   N)rV   rW   rX   rY   ÚpropertyrZ   rm   r%   r+   r9   r.   rj   rj   �   s9   „ á\àð�sò ó ðð ð)˜ò )ó ñ)r9   rj   c                   óR   — e Zd ZU dZeg ef   ed<   edefd„«       Zedefd„«       Z	y)ÚAzureEntraTokenAuthzÝAzure Database for PostgreSQL auth: a Microsoft Entra ID access token as the password.

    The provider is injected rather than resolved here so callers (and tests) decide which
    Azure credential mints the token.
    Útoken_providerr&   c                  ó   — y)NzAzure Entra tokenr+   rl   s    r.   rm   zAzureEntraTokenAuth.label¤   s   € à"r9   c                 ó   — t         S r*   )r   rl   s    r.   r%   zAzureEntraTokenAuth.env_var¨   s   € ä,Ð,r9   N)
rV   rW   rX   rY   r   rZ   r[   ro   rm   r%   r+   r9   r.   rq   rq   š   sL   … ñð ˜R ˜WÑ%Ó%àð#�sò #ó ð#ð ð-˜ò -ó ñ-r9   rq   ÚDatabaseTokenAuthÚauthÚendpointc                 óâ   — | xt         d˜ x�2\    ddlm}  ||j                  |j                  |j
                  ¬«      S  t        d˜ x�\   t        | j                  «       «      S  	 t        | «       y)zIMint a fresh database password for ``endpoint``, already percent-encoded.r+   Nr   )Úgenerate_iam_auth_token)Údb_hostÚdb_portÚdb_user)
rj   Ú litellm.proxy.auth.rds_iam_tokenry   rI   rJ   rK   rq   rA   rr   r   )rv   rw   ry   s      r.   Úmint_database_tokenr~   °   s_   € à
ØŒ_ÖÝPá*°8·=±=È(Ï-É-Ðai×anÑanÔoÐoð ô !Õ"Ü˜$×-Ñ-Ó/Ó0Ð0ð #àÜ˜Õr9   rN   c                 ó~   — | xt         d˜ x�\    t        |«      S  t        d˜ x�\   t        |«      S  	 t	        | «       y)zÝReturn when ``token`` expires as a naive UTC datetime, or None when unreadable.

    Callers fall back to a fixed refresh interval on None, so an unparseable token
    degrades to periodic refresh instead of failing.
    r+   N)rj   Ú_parse_rds_token_expirationrq   Ú_parse_entra_token_expirationr   )rv   rN   s     r.   Úparse_database_token_expirationr‚   ½   s@   € ð ØŒ_ÖÜ.¨uÓ5Ð5ð ä Õ"Ü0°Ó7Ð7ð #àÜ˜Õr9   c                 ó–  — d| vry 	 t         j                  j                  | j                  dd«      d   «      }|j	                  d«      }|j	                  d«      }|r|sy t        j                  |d   d«      }|t        t        |d   «      ¬«      z   S # t        t        t        f$ r }t        j                  d|«       Y d }~y d }~ww xY w)	Nú?é   zX-Amz-Expiresz
X-Amz-Dater   z%Y%m%dT%H%M%SZ)Úsecondsz,Failed to parse RDS IAM token expiration: %s)r=   r>   rd   Úsplitre   r   Ústrptimer   Úintr4   ÚOverflowErrorÚOSErrorr   Údebug)rN   ÚparamsÚexpires_valuesÚdate_valuesÚcreatedÚexcs         r.   r€   r€   Ì   s·   € Ø
�%ÑØð
ÜŸ™×-Ñ-¨e¯k©k¸#¸qÓ.AÀ!Ñ.DÓEˆØ &§
¡
¨?Ó ;ˆØ#ŸZ™Z¨Ó5ˆÙ¡[ØÜ!×*Ñ*¨;°q©>Ð;KÓLˆØœ¬3¨~¸aÑ/@Ó+AÔBÑBÐBøÜœ¤wÐ/ò Ü×"Ñ"Ð#QÐSVÔWÜûðús   ‡AB Á 3B ÂCÂ(CÃCc                   ó   — e Zd ZU eed<   y)Ú_EntraAccessTokenClaimsÚexpN)rV   rW   rX   r‰   r[   r+   r9   r.   r“   r“   Ü   s   … Ø	„Hr9   r“   c           	      óš  — | j                  d«      }t        |«      dk7  ry |d   }	 t        j                  t	        j
                  |dt        |«       dz  z  z   «      «      }t        j                  |j                  t        j                  ¬«      j                  d ¬«      S # t        $ r }t        j                  d|«       Y d }~y d }~ww xY w)	Nú.é   r…   r(   é   z0Failed to parse Azure Entra token expiration: %s)Útz)Útzinfo)r‡   Úlenr“   Úmodel_validate_jsonÚbase64Úurlsafe_b64decoder4   r   rŒ   r   Úfromtimestampr”   r   ÚutcÚreplace)rN   ÚsegmentsÚpayloadÚclaimsr‘   s        r.   r�   r�   à   s²   € Ø—k‘k #Ó&€HÜ
ˆ8ƒ}˜ÒØØ˜a‘[€GðÜ/×CÑCÜ×$Ñ$ W¨s´s¸7³|°mÀaÑ6GÑ/HÑ%HÓIó
ˆô ×!Ñ! &§*¡*´·±Ô>×FÑFÈdÐFÓSÐSøô ò Ü×"Ñ"Ð#UÐWZÔ[Üûðús   §;B! Â!	C
Â*CÃC
c                  ó(   — ddl m}   | t        ¬«      S )aG  The process-wide Entra token provider for the Azure Postgres OSS RDBMS scope.

    Cached because the writer URL, the reader URL, and the refresh loop each ask for a
    strategy, and every uncached call would build another Azure credential with its own
    HTTP transport and its own token cache that nothing ever closes.
    r   ©Úget_azure_ad_token_provider)Úazure_scope)Ú3litellm.secret_managers.get_azure_ad_token_providerr§   r   r¦   s    r.   Ú build_azure_entra_token_providerrª   ï   s   € õñ 'Ô3IÔJÐJr9   Úiam_token_db_authÚazure_postgresql_authc                 ón   — | r|rt        t        «      ‚|rt        t        «       ¬«      S | r
t	        «       S y)zLPick the token strategy the two toggles ask for, or None when neither is on.)rr   N)ÚRuntimeErrorr   rq   rª   rj   ©r«   r¬   s     r.   Úbuild_database_token_authr°   þ   s5   € áÑ2ÜÔ9Ó:Ð:ÙÜ"Ô2RÓ2TÔUÐUÙÜÓ Ð Ør9   c                  ó´   — t        t        t        j                  t        «      t        ¬«      t        t        j                  t
        «      t
        ¬«      ¬«      S )zSResolve the token strategy from the environment, raising when both toggles are set.)r%   r¯   )r°   r8   ÚosÚgetenvr   r   r+   r9   r.   Úresolve_database_token_authr´   	  sA   € ä$Ü1Ü�I‰IÔ/Ó0Ô:Sô
ô 6Ü�I‰IÔ3Ó4Ô>[ô
ô	ð r9   )2rY   r�   Ú	functoolsr²   Úurllib.parser=   Úcollections.abcr   Údataclassesr   r   r   r   Útypingr   r	   Úpydanticr
   Útyping_extensionsr   Úlitellm._loggingr   r   r[   r   r   r   r   Ú	frozensetr   rZ   r#   r1   r8   rA   rD   rH   rh   rj   rq   ru   r~   r‚   r€   r“   r�   Úcacherª   r°   r´   r+   r9   r.   ú<module>r¿      s~  ðòó Û Û 	Û Ý $Ý !ß 2Ñ 2ß #å Ý *å 1à#6Ð ˜5Ó 6Ø'>Ð ˜uÓ >Ø TÐ ˜Ó Tð !Ð! Ð'DÐ&Eð FCà Ð!Ð!;Ð<YÐ;Zð [VðVð  ó ð  &Ð �uÓ %á2;Ò<`Ó2aÐ ˜% 	¨#¡Ñ/Ó aÙ1:Ò;dÓ1eÐ ˜˜y¨™~Ñ.Ó eð 3¨¡:°Ñ#4ð À#ð È$ó ð8.�#ð .˜#ó .ðD˜Cð D Có Dñ �$˜dÔ#÷@ð @ó $ð@ð@ Sð ¨[ó ñ. �$˜dÔ#÷	)ð 	)ó $ð	)ñ �$˜dÔ#÷-ð -ó $ð-ð$  /Ð1DÑDÐ �9Ó Dð
Ð/ð 
¸;ð 
È3ó 
ðÐ*;ð ÀCð ÈHÐW[ÉOó ð sð ¨x¸$©ó ô ˜iô ðT¨ð T°¸D±ó Tð ‡�ðK¨(°2°s°7Ñ*;ò Kó ðKð°Dð ÐQUð ÐZkÐnrÑZró ð	Ð%6¸Ñ%=ô 	r9   