
    Áj¡                       U d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
mZmZmZmZmZmZ d dlmZ d dlZddlmZmZ ddlmZmZmZmZmZmZ ddlmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 d	d
l5m6Z6  ejn                  e8      Z9de:d<   erddl;m<Z< g dZ=ddZ>dZ?dZ@dZAdZBdZCd dZD G d d      ZE G d d      ZF G d d      ZG G d d      ZH G d deG      ZIy)!    )annotationsN)TYPE_CHECKINGAnyDictUnionOptionalcast)override   )AccessTokenIdentityTokenProvider)	SecretStr_unwrap_secret_strip_traceback_json_dumps_secrets_wrap_secret_fields_NonObjectPayloadError)	ENV_SCOPEENV_PROFILEENV_BASE_URLENV_AUTH_TOKENENV_CONFIG_DIRTOKEN_ENDPOINTDEFAULT_BASE_URLENV_WORKSPACE_IDENV_ORGANIZATION_IDOAUTH_API_BETA_HEADERENV_FEDERATION_RULE_IDENV_SERVICE_ACCOUNT_IDTOKEN_EXCHANGE_TIMEOUTENV_IDENTITY_TOKEN_FILEGRANT_TYPE_REFRESH_TOKENMANDATORY_REFRESH_SECONDS_user_agent_require_https_active_profile_config_file_path_credentials_file_pathresolve_identity_token_path   )AnthropicErrorzlogging.Loggerlog)WorkloadIdentityCredentials)StaticTokenEnvTokenCredentialsFileInMemoryConfigIdentityTokenFilec                    | y	 t        |       S # t        t        f$ r }|d| nd}t        | d| d      |d}~ww xY w)z@Parse a credentials-file ``expires_at`` field into Unix seconds.Nzcredentials file at credentialsz has invalid 'expires_at' u   ; expected an integer Unix timestamp in seconds. The SDK does not parse ISO8601 — convert with int(datetime.timestamp()) before writing the file.)int	TypeError
ValueErrorr+   )valuesourceerrwheres       K/tmp/pip-target-k_scjv0h/lib/python/anthropic/lib/credentials/_providers.py_coerce_expires_atr=   ;   sl    }5zz" 393E&vh/=g/y 9F G
 		s   
 ?:?oauth_tokenz1.0oidc_federation
user_oauthc                   dd} || dt                 || dt                || dt               |j                  d      }|t        k(  rk ||dt
                ||dt                ||dt               |j                  d	      s/t        j                  j                  t              }|r	d
|d|d	<   yyy|t        k(  r ||dt               yy)u   Fill empty profile fields from corresponding ANTHROPIC_* env vars.

    The profile file is authoritative — this only fills fields the file left
    unset. Empty-string env values are treated as unset.
    c                v    | j                  |      s(t        j                  j                  |      }|r|| |<   y y y N)getosenviron)targetkeyenv_varvs       r<   fillz$_fill_missing_from_env.<locals>.fill^   s5    zz#

w'As      base_urlorganization_idworkspace_idtypefederation_rule_idservice_account_idscopeidentity_tokenfile)r9   pathN)rG   Dict[str, Any]rH   strrI   rX   returnNone)r   r   r   rD   AUTH_TYPE_OIDC_FEDERATIONr   r   r   rE   rF   r!   AUTH_TYPE_USER_OAUTH)configauthrK   	auth_typerJ   s        r<   _fill_missing_from_envr`   W   s      	\*"$78!12 I--T')?@T')?@T7I&xx()

67A4:A)F%&  * 
*	*T7I& 
+rL   c                  &    e Zd ZdZddZddddZy)	r.   zQAn :class:`AccessTokenProvider` that always returns a fixed token with no expiry.c                    || _         y rC   )_token)selftokens     r<   __init__zStaticToken.__init__y   s	    rL   Fforce_refreshc               2    ~t        | j                  d       S )Nre   
expires_at)r   rc   )rd   rh   s     r<   __call__zStaticToken.__call__|   s    >>rL   N)re   rX   rY   rZ   rh   boolrY   r   )__name__
__module____qualname____doc__rf   rl    rL   r<   r.   r.   v   s    [ 16 ?rL   r.   c                  *    e Zd ZdZefddZddddZy)	r/   zQAn :class:`AccessTokenProvider` that reads ``ANTHROPIC_AUTH_TOKEN`` at call time.c                    || _         y rC   )_env_var)rd   rI   s     r<   rf   zEnvToken.__init__   s	    rL   Frg   c                   ~t         j                  j                  | j                        }|t	        d| j                   d      t        |d       S )NzEnvironment variable zN is not set. Set it or pass an explicit `credentials=` provider to the client.rj   )rE   rF   rD   rv   r+   r   )rd   rh   r8   s      r<   rl   zEnvToken.__call__   sS    

t}}-= ' 7T U  488rL   N)rI   rX   rY   rZ   rm   )ro   rp   rq   rr   r   rf   rl   rs   rL   r<   r/   r/      s    [&4   16 9rL   r/   c                      e Zd ZdZ	 ddd	 	 	 	 	 ddZedd       Zedd       Zedd       ZddZ	d d	Z
d!d
Zd"dZd#dZd#dZd$dZd%dZd%dZd&dZd#dZddd'dZddd(dZd)dZddd(dZd*dZy)+r0   u  An :class:`AccessTokenProvider` backed by a named profile.

    A profile is a pair of files under the config directory
    (``~/.config/anthropic/`` by default; override with ``ANTHROPIC_CONFIG_DIR``):

    * ``configs/<profile>.json`` — non-secret. Holds the nested
      ``"authentication"`` object (discriminated by its ``"type"`` field), plus
      top-level ``organization_id``, ``workspace_id``, and ``base_url``.
      The ``authentication`` object may contain a ``credentials_path`` field
      overriding the credentials file location.
    * ``credentials/<profile>.json`` — secret (0600). Holds ``access_token``,
      ``expires_at``, and (for ``user_oauth`` with a ``client_id``)
      ``refresh_token``.

    The split keeps secret material out of files that may need to be readable
    by config-only consumers, and lets the SDK enforce 0600 on the credentials
    file without locking out config readers.

    Dispatches on the ``authentication.type`` discriminator:

    ``"oidc_federation"``
        OIDC workload identity federation. Lazily constructs a
        :class:`WorkloadIdentityCredentials` delegate from the nested auth
        fields plus the top-level ``organization_id`` and calls it to perform
        the jwt-bearer exchange.

    ``"user_oauth"``
        Output of an interactive PKCE login. If the auth block has a
        ``client_id``, performs ``refresh_token`` grants on expiry and
        writes the new tokens back to the credentials file (atomic replace,
        refresh-token rotation supported). Without a ``client_id``, the
        credentials file is treated as externally rotated — the SDK re-reads
        it on every invocation and returns whatever ``access_token`` is
        there, no refresh grant attempted. This is the pattern for a
        sidecar/daemon that mints the access token out-of-band.

    Args:
        profile: Profile name. ``None`` resolves via ``ANTHROPIC_PROFILE`` env
            → ``<config_dir>/active_config`` pointer file → ``"default"``.
    N)http_clientc                   ||n	t               | _        t        | j                        | _        d | _        || _        d | _        d | _        d | _        t        | _
        d | _        y rC   )r&   _profiler'   _config_path_bound_base_url_http_client_owned_http_client_config_credentials_pathr   	_base_url_workload_delegate)rd   profilery   s      r<   rf   zCredentialsFile.__init__   s^     $+#6O<M-dmm<.2':> 269=.IMrL   c                    | j                   S rC   )r{   rd   s    r<   r   zCredentialsFile.profile   s    }}rL   c                    | j                   S rC   )r|   r   s    r<   config_pathzCredentialsFile.config_path   s       rL   c                    | j                         }|j                  d      }|rt        |      j                  d      S dS )u  The ``base_url`` declared in the profile config file, if any.

        Returns ``None`` when the config has no top-level ``base_url`` key —
        callers should fall back to their own default rather than the
        provider's bound/default value, so a profile that *doesn't* pin a
        host never overrides an explicit client setting. Loads the config
        on first access.
        rM   /N)_load_configrD   rX   rstrip)rd   r]   raws      r<   resolved_base_urlz!CredentialsFile.resolved_base_url   s:     ""$jj$'*s3xs#44rL   c                
   |j                  d      }t        || j                   d       || _        | j                  E| j                  | j                        | _        t        | j                  | j                   d       yy)a`  Adopt the owning client's ``base_url`` as a fallback for the token
        exchange. Slots between the config file's own ``base_url`` field and
        the hard-coded default; a ``base_url`` in the config file still wins.

        Rebinding affects every client holding this instance; clients bind
        through :meth:`for_base_url` instead.
        r   
: base_urlfieldN)r   r%   r|   r}   r   _resolve_base_urlr   )rd   rM   bounds      r<   bind_base_urlzCredentialsFile.bind_base_url   su     $ 	ut'8'8&9$DE$<<#!33DLLADN4>>D4E4E3Fj1QR $rL   c                   |j                  d      }| j                  | j                  |k(  r| j                  |       | S | j                         }|j	                  d      s&| j                         j	                  d      t        k7  r| S t        j                  |       }| j                         |_	        d|_
        d|_        d|_        |j                  |       |S )a  Return the provider a client with ``base_url`` should exchange through.

        Binds in place, unless another client already bound this instance to a
        different host (e.g. the parent of ``copy(base_url=...)``). That binding
        is left alone, and what happens depends on the profile:

        * pins its own ``base_url``: the bind is irrelevant, return ``self``.
        * ``oidc_federation``: return a copy bound to ``base_url``. It shares the
          identity token and http client, but not the on-disk token cache, whose
          tokens belong to the original deployment.
        * ``user_oauth``: return ``self``. The refresh token is tied to the
          deployment that issued it, so there is nothing per-host to copy.
        r   NrM   rP   )r   r}   r   r   rD   _auth_blockr[   copy_get_http_clientr~   r   r   r   )rd   rM   r   r]   providers        r<   for_base_urlzCredentialsFile.for_base_url   s     $'4+?+?5+Hu%K""$::j!T%5%5%7%;%;F%CG`%`K99T? $ 5 5 7&*#&*#%)"u%rL   c                    |j                  d      rt        |d         j                  d      S | j                  | j                  S t        S )u+  base_url precedence: top-level config field → bound (the owning
        client's base_url, via :meth:`bind_base_url`) → default. Validated
        against the scheme/TLS rules so a malicious config with
        ``base_url="http://evil/"`` can't exfiltrate the assertion or refresh
        token.rM   r   )rD   rX   r   r}   r   rd   r]   s     r<   r   z!CredentialsFile._resolve_base_url  sI     ::j!vj)*11#66+'''rL   c                    | j                         }i }| j                         j                  d      t        k7  r!|j                  d      }|rt	        |      |d<   |S )zReturn headers derived from the config file (e.g. ``workspace_id``).

        Eagerly reads the config if not yet loaded. The returned dict is
        suitable for merging into the client's default headers.
        rP   rO   zanthropic-workspace-id)r   r   rD   r[   rX   )rd   r]   headersrO   s       r<   extra_headerszCredentialsFile.extra_headers  s\     ""$"$ !!&)-FF!::n5L474E01rL   c                   | j                   | j                   S 	 | j                  j                  d      }	 t        j                  |      }t        |t              s/t	        d	| j                   dt        |      j                    d      t#        d|      }|j%                  d      }t        |t              s't	        d	| j                   dt&         dt(         d      t#        d|      }t+        ||       | j-                  |      | _        t1        | j.                  | j                   d       |j%                  d      }|r2t3        j4                  t7        |            j9                         | _        nt=        | j
                        | _        || _         |S # t        $ r:}t	        d| j                   d| j
                  dt         dt         d	      |d}~wt        t        f$ r!}t	        d	| j                   d
|       |d}~ww xY w# t        j                  $ r!}t	        d	| j                   d|       |d}~ww xY w)zPRead and cache the config file, resolving ``base_url`` and ``credentials_path``.Nutf-8encodingzConfig file not found at 
 (profile z). Set z' to select a different profile, or set z" to relocate the config directory.zConfig file at  could not be read:  is not valid JSON: ! must contain a JSON object, not .rW   authenticationzV is missing the 'authentication' object. Expected shape: {"authentication": {"type": ""|"", ...}, ...}r   r   credentials_path)r   r|   	read_textFileNotFoundErrorr+   r{   r   r   OSErrorUnicodeDecodeErrorjsonloadsJSONDecodeError
isinstancedictrP   ro   r	   rD   r[   r\   r`   r   r   r%   pathlibPathrX   
expanduserr   r(   )rd   r   r:   
raw_configr]   raw_authr^   r
   s           r<   r   zCredentialsFile._load_config2  sP   <<#<<		j##--w-?C	j"jjoJ *d+ !$"3"3!44UVZ[eVfVoVoUppqr  &
3::./(D) !$"3"3!4 5-.c2F1GX 
 $h/ 	vt,//7t~~0A0A/B*-MN88./%,\\#h-%@%K%K%MD"%;DMM%JD"U ! 	 +D,=,=+>jHY Z"m#J>JZ [45 	
 +, 	j ?43D3D2EEYZ]Y^!_`fii	j ## 	j ?43D3D2EEYZ]Y^!_`fii	js:   F H 	H
"5GH
)HH
I H<<Ic           	        | j                   J | j                   }t        j                  dk(  r	 t        j                  |d      }t        j                  |j                        rt        d| d
      t        j                  |j                        }|dz  rt        d| d|dd| d      |dz  rt        j                  d|||       	 t        t        j                  |j!                  d                  }|j-                  d      }|M|t.        k7  rD| j0                  J | j0                  d   j-                  d      }t        d|dt.        d|      |S # t        $ r"}t        d| d| j                  d      |d}~wt        $ r}t        d| d	|       |d}~ww xY w# t        $ r"}t        d| d| j                  d      |d}~wt        j"                  $ r }t        d| d|       t%        |      d}~wt&        $ r"}t        d| d|j(                   d      dd}~wt        t*        f$ r}t        d| d|       |d}~ww xY w)u  Read the credentials file. Re-reads on every call — daemons rotate it.

        Secret values in the returned dict (every string field not in
        ``_secrets._PLAIN_KEYS``) are :class:`SecretStr`-wrapped — unwrap
        with ``_unwrap_secret`` at the point of use. Writing the dict back
        through :meth:`_atomic_write_credentials` unwraps automatically.

        On Unix, verifies the file is not group/world-readable. World-readable
        credentials files are refused outright; group-readable files log a
        warning but are accepted. The check is skipped on Windows where POSIX
        mode bits don't carry the same meaning.
        NposixF)follow_symlinkszCredentials file not found at r   ).Credentials file at z could not be accessed: zu is a symlink; refusing to follow (move the real file into place to keep secret material on the expected filesystem).   z is world-readable (mode z#oz); run `chmod 600 z` before retrying.8   zMCredentials file at %s is group-readable (mode %#o); consider `chmod 600 %s`.r   r   r   r   r   r   rP   r   zcredentials file has type z; expected z for authentication.type )r   rE   namestatr   r+   r{   r   S_ISLNKst_modeS_IMODEr,   warningr   r   r   r   r   r   r   	type_namer   rD   CREDENTIALS_FILE_TYPEr   )rd   rV   	file_statr:   modecredsactualr_   s           r<   _read_credentialsz!CredentialsFile._read_credentialse  s    %%111%%77gjGGD%@	
 ||I--.$*4& 1j k  <<	 1 12De|$*4&0I$r S&&*V+=?  e|c		b
 %8

4>>[b>Cc8d$eE" 6"&,A"A<<+++%56::6BI ,VJkBWAZ [++4-9  i % t$'EdV:VZVcVcUffh%ijpss j$';D6AYZ]Y^%_`fiij4 ! 	p #A$zRVR_R_Qbbd!efloo## 	t #7v=QRUQV!WX^nor^ss% 	 !&tf,Mcmm_\]^ +, 	b #7v=QRUQV!WX^aa	bs_   E .F( 	F%%FF%F  F%(	I1GI$G??IH((I:IIc                    | j                   | j                   S | j                  t        j                  t              | _        | j                  S )zFReturn an ``httpx.Client``, lazily creating (and tracking) one we own.)timeout)r~   r   httpxClientr    r   s    r<   r   z CredentialsFile._get_http_client  sD    ($$$""*&+ll;Q&RD#&&&rL   c                    | j                   !| j                   j                          d| _         | j                  | j                  j                          yy)z3Close the owned ``httpx.Client`` if we created one.N)r   closer   r   s    r<   r   zCredentialsFile.close  sK    "".##))+&*D#"".##))+ /rL   c                     d| _         d| _        y)a  Drop the cached config so the next call re-reads it from disk.

        ``CredentialsFile`` caches the parsed config across calls to keep the
        hot path cheap; a daemon that rotates a profile in place (e.g. flips
        ``"type": "user_oauth"`` to ``"type": "oidc_federation"``) will not be
        picked up automatically. Callers that need to react to such changes
        can call ``reload()`` to force a fresh read on the next ``__call__``.
        N)r   r   r   s    r<   reloadzCredentialsFile.reload  s     "&rL   c                l   | j                   J | j                   j                  }|j                  ddd       t        j                  |d| j                   j
                   dd      \  }}	 	 t        j                  |d       t        j                  |t        |d	
             t        j                  |       t        j                  |       t        j                  || j                          	 t        j                   |t        j"                        }	 t        j                  |       t        j                  |       y# t        j                  |       w xY w# t        $ r' 	 t        j                  |        # t        $ r Y  w xY ww xY w# t        j                  |       w xY w# t        $ r Y yw xY w)ai  Atomic write to the credentials file (NOT the config file).

        ``data`` may hold :class:`SecretStr` token values (see
        :meth:`_read_credentials`); they are unwrapped at dump time, so the
        on-disk format is unchanged and this frame's locals stay redacted if
        the write fails (e.g. ENOSPC) with a crash reporter capturing them.
        NTi  )parentsexist_okr   r   z.tmp)dirprefixsuffixi     )indent)r   parentmkdirtempfilemkstempr   rE   fchmodwriter   fsyncr   replaceBaseExceptionunlinkr   openO_RDONLY)rd   datar   fdtmpdir_fds         r<   _atomic_write_credentialsz)CredentialsFile._atomic_write_credentials  sb    %%111''..TDu=
 ""v$:P:P:U:U9VVW6XaghC			"e$0a@AJJsD223	WWVR[[1F!  !  			#   	   		sm   .AE  :5E 0$F' F *F'  EE 	F
$E:9F
:	FF
FF
F$$F' '	F32F3c                @    | j                         }t        d|d         S )zEReturn the cached ``authentication`` sub-object from the config file.rW   r   )r   r	   r   s     r<   r   zCredentialsFile._auth_block  s$    ""$$f-=&>??rL   Frg   c                  | j                         }|j                  d      }|t        k(  r| j                  ||      S |t        k(  r| j                  ||      S t        d|d| j                   dt        dt        d	      )NrP   rg   Unknown authentication.type  at . Expected  or r   )r   rD   r[   _call_oidc_federationr\   _call_user_oauthr+   r|   )rd   rh   r^   r_   s       r<   rl   zCredentialsFile.__call__  s    !HHV$	11--d--PP,,((](KK*9-tD<M<M;N O14D9M8PPQS
 	
rL   c                  ddl m}m}m} | j	                         }|j                  d      }|st        d| j                   d      |j                  d      }|s;t        |j                  d      | j                        }	t        t        |      |	      S |j                  d	      }
|
s) |d
| j                  dt        d| j                         t        |j                  d      | j                        }	|s/|	-t        j                         |	k  rt        t        |      |	      S t        |
|d}	 | j                         j!                  | j"                   t$         t'        |      dt(        t+               d      }|j2                  dk7  r
 ||d       	 t5        |j7                               }|j                  d      }|s |d      |j                  dd      }	 t?        |      }t?        t        j                               |z   }|j                  d	      xs |
}tB        |d!<   tD        |d"<   ||d<   ||d<   ||d	<   | jG                  |       t        t        |      |      S # t,        j.                  $ r} |d|       t1        |      d}~ww xY w# t8        $ r8} |d|j2                   d|j2                   ||            t1        |      d}~wt:        $ r<} |d|j<                   d|j2                   d|j2                   ||            dd}~ww xY w# t@        t8        f$ r} |d|d       |d}~ww xY w)#zInteractive-login profile. With a ``client_id`` in the auth block,
        we run the refresh_token grant on expiry; without one, we treat the
        credentials file as externally rotated and just read it fresh.
        r   )WorkloadIdentityError_request_id_raise_token_endpoint_erroraccess_tokenr   z is missing 'access_token'.	client_idrk   rj   refresh_tokenzcredentials file for profile z (authentication.type z/ with client_id) must include 'refresh_token': N)
grant_typer   r   zapplication/json)zContent-Typezanthropic-betaz
User-Agent)contentr   z3user_oauth refresh failed to reach token endpoint:    zuser_oauth refresh failed)message_prefixz8user_oauth refresh returned a non-JSON response (status r   )status_code
request_idz#user_oauth refresh returned a JSON z	 (status z); expected an object.z2user_oauth refresh response missing 'access_token'
expires_ini  z5user_oauth refresh response has invalid 'expires_in' z(; expected an integer number of seconds.versionrP   )$	_workloadr   r   r   r   rD   r+   r   r=   r   r   r{   r\   timer"   r   postr   r   r   r   r$   r   	HTTPErrorr   r  r   r   r7   r   r   r5   r6   CREDENTIALS_FILE_VERSIONr   r   )rd   r^   rh   r   r   r   r   r   r   rk   r   bodyrespr:   payload
new_accessraw_expires_inr  new_expires_atnew_refreshs                       r<   r   z CredentialsFile._call_user_oauth  sn   
 	_^&&(yy0 #78N8N7OOj!kllHH[)	 ,EIIl,CTE[E[\J^L%AjYY		/2'//@@V'**Y))*,  (		,(?AWAWX
!7DIIK*<T^L%AjYY 3*"2
	)((*//>>">"23 ,D1$6
 '<"-- 0 D( s"'=XY	&9$))+&FG$ [[0
'(\]] \48	^,J TYY[)J6kk/2Cm3i-f *n,l!,o 	&&u-
!;WWe  	)'EcUK#C()	)  	) (J4K[K[J\\^_ ,,&t, $C(	)
 & 	 (5cmm_IdN^N^M__uv ,,&t, 		 :& 	'GGY Z9 : 	sU   2AI( J  L (J;JJ	L!3KL 7LLM .L;;M c                    | j                   J | j                   j                         sy	 | j                         S # t        $ r%}t	        |j
                  t              rY d}~y d}~ww xY w)u   ``_read_credentials`` variant that returns ``None`` on absence
        instead of raising — used by the federation disk-cache path where a
        missing credentials file just means "exchange now".
        N)r   existsr   r+   r   	__cause__r   )rd   r:   s     r<   _read_credentials_if_existsz+CredentialsFile._read_credentials_if_exists{  sd    
 %%111%%,,.	))++ 	#--):;	s   ; 	A)A$#A$$A)c                  | j                   | j                  |      | _         | j                  | j                         S | j                         }|sx|v|j	                  d      }|j	                  d      }	 |rQ|Ot        j
                         t        |      t        z
  k  r(t        t        t        |            t        |            S | j                         }	 | j                  i |xs i t        t         t#        |j$                        |j&                  d       |S # t        t        f$ r Y gw xY w# t(        $ r!}t*        j-                  d|       Y d }~|S d }~ww xY w)Nr   rk   rj   )r  rP   r   rk   z?federation token disk-cache write-back failed (best-effort): %s)r   _build_workload_delegater   r  rD   r	  floatr#   r   rX   r   r5   r6   r7   r   r  r   r   re   rk   r   r,   debug)rd   r^   rh   cachedr   rk   re   r:   s           r<   r   z%CredentialsFile._call_oidc_federation  sY   ""*&*&C&CD&ID# !!)**,, 113!3!::n5LL1J	 ".		eJ&7:S&SS&S1M-N[^_i[jkk
 '')	^**|71 %.ekk$:"'"2"2
 ' z* "  	^IIWY\]]	^s,   6AD AD4 D10D14	E=EEc           
        ddl m}m} |j                  d      }| j                  J | j                  j                  d      }|r|s |dt
        d| j                         |j                  d      }|a|j                  d      }|d	k7  rt        d
|d      |j                  d      }|s+t        d| j                  d| j                   d|d      d }|rt        |      n	t               }	 ||	|||j                  d      | j                  j                  d      |j                  d      | j                               }
|
j                  | j                         |
S )Nr   r   r-   rQ   rN   z%config file with authentication.type zS must include 'authentication.federation_rule_id' and top-level 'organization_id': rT   r9   rU   zidentity_token source z- is not supported; only 'file' is implementedrV   z@identity_token source 'file' requires a non-empty path; profile r   z has identity_token=r   rR   rO   rS   identity_token_providerrQ   rN   rR   rO   rS   ry   )r  r   r-   rD   r   r[   r|   r+   r{   r2   r   r   r   )rd   r^   r   r-   rQ   rN   identity_token_cfgr9   identity_token_pathr   delegates              r<   r  z(CredentialsFile._build_workload_delegate  s    	R!XX&:;||''',,**+<=!'78Q7T UX$$%'  "XX&67)'++H5F$'=fZGt%uvv"4"8"8"@& %#}}/tD4E4E3FFZ[mZppqs 
 #'=P$%89VgVi
 /$,1+#xx(<=)).9((7#--/
 	t~~.rL   rC   )r   Optional[str]ry   Optional[httpx.Client]rY   rZ   rY   rX   rY   zpathlib.Path)rY   r$  )rM   rX   rY   rZ   )rM   rX   rY   z'CredentialsFile')r]   rW   rY   rX   )rY   zDict[str, str]rY   rW   )rY   zhttpx.ClientrY   rZ   )r   rW   rY   rZ   rm   )r^   rW   rh   rn   rY   r   )rY   zOptional[Dict[str, Any]]r^   rW   rY   r-   )ro   rp   rq   rr   rf   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   r   rl   r   r  r   r  rs   rL   r<   r0   r0      s    'V "&N /3	NN ,	N
 
N&   ! ! 5 5S":
 &1fFP',
'(X@
 16 
" OT lX` TY .`3rL   r0   c                  4    e Zd ZdZdddZedd       Zd	dZy)
r2   zAn :class:`IdentityTokenProvider` that reads a JWT from a file on every call.

    Kubernetes projected service-account tokens (and similar) are rotated in place,
    so the file MUST be re-read on every invocation rather than cached.
    Nc                R    t        |      }|t        dt         d      || _        y )Nz;No identity token file path given. Pass `path=` or set the z environment variable.)r)   r+   r!   _path)rd   rV   resolveds      r<   rf   zIdentityTokenFile.__init__  s<    .t4 MNeMf g( )  
rL   c                    | j                   S rC   )r.  r   s    r<   rV   zIdentityTokenFile.path   s    zzrL   c                   	 | j                   j                  d      j                         }|st	        d| j                    d      |S # t        $ r}t	        d| j                    d      |d }~wt
        $ r"}t	        d| j                    d| d      |d }~wt        $ r}t	        d| j                    d	      |d }~wt        t        f$ r!}t	        d| j                    d
|       |d }~ww xY w)Nr   r   z!Identity token file not found at r   zIdentity token file at z" is not readable by this process: z;. Check the file mode and the effective uid of the process.zIdentity token path zF is a directory, not a file. Point at the projected token file itself.r   z is empty. If this is a Kubernetes projected service-account token, check the volume mount and the serviceAccountToken projection audience.)	r.  r   stripr   r+   PermissionErrorIsADirectoryErrorr   r   )rd   r  r:   s      r<   rl   zIdentityTokenFile.__call__  s,   	kjj**G*<BBDG  )$** 6P Q 
 ) ! 	] #DTZZLPQ!RSY\\ 	 )$**5WX[W\ ]L M  ! 	 &tzzl 3< =  +, 	k #:4::,FZ[^Z_!`agjj	ks;   *A	 		C.A,,C.8BC.!B;;C.C))C.rC   )rV   z$Union[str, 'os.PathLike[str]', None]rY   rZ   r'  r&  )ro   rp   rq   rr   rf   r+  rV   rl   rs   rL   r<   r2   r2     s%      rL   r2   c                       e Zd ZdZ ej
                  d      Zddd	 	 	 	 	 	 	 d	dZed
d       Z	edd       Z
ed fd       Z xZS )r1   u  An :class:`AccessTokenProvider` driven by an in-memory config dict
    (same shape as ``configs/<profile>.json``) rather than files on disk.

    Intended for callers that want to construct an :class:`anthropic.Anthropic`
    client with a fully programmatic credentials setup — equivalent to the Go
    SDK's ``option.WithConfig`` / TypeScript SDK's ``ClientOptions.config``.

    Both ``authentication.type`` discriminator values are supported:

    ``"oidc_federation"``
        ``authentication.credentials_path`` is **optional**. If set, exchanged
        tokens are cached to / read from that file (same atomic 0600 write as
        :class:`CredentialsFile`). If omitted, every call performs a fresh
        jwt-bearer exchange with no on-disk cache.

    ``"user_oauth"``
        ``authentication.credentials_path`` is **required** — it is where the
        access/refresh tokens live. Behaviour is identical to a file-backed
        :class:`CredentialsFile` profile of the same shape.

    The implementation subclasses :class:`CredentialsFile` so the dispatch,
    refresh-grant, disk-cache and atomic-write logic are shared verbatim;
    only config loading and identity-token resolution are overridden.
    z<in-memory config>N)r   ry   c          	        |j                  d      }t        |t              st        dt         dt
         d      t        d|      }|j                  d      }|t        t
        fvrt        d|dt        d	t
        d
      |j                  d      }|t
        k(  r|st        dt
        d      d| _        | j                  | _	        d | _
        || _        d | _        d | _        || _        || _        |r,t!        j"                  t%        |            j'                         nd | _        | j+                  |      | _        t/        | j,                  d       y )Nr   zaconfig dict is missing the 'authentication' object. Expected shape: {"authentication": {"type": "r   r   rW   rP   r   r   r   r   r   zauthentication.type z requires 'authentication.credentials_path' (where the access/refresh tokens live). For profile-based resolution, use CredentialsFile instead.z<in-memory>zconfig: base_urlr   )rD   r   r   r+   r[   r\   r	   r{   _IN_MEMORY_PATHr|   r}   r~   r   r   !_identity_token_provider_overrider   r   r   rX   r   r   r   r   r%   )rd   r]   r   ry   r   r^   r_   r   s           r<   rf   zInMemoryConfig.__init__:  sq    ::./(D) BB[A\ ])*/; 
 $h/HHV$	68LMM .ym <58=Q<TTUW 
  88$67,,5E &';&> ?M N  & 00.2':>IM1H.Uec2B.C!D!O!O!Qko//7t~~-?@rL   c                6    | j                   J | j                   S rC   )r   r   s    r<   r   zInMemoryConfig._load_configg  s    ||'''||rL   c                    d | _         y rC   )r   r   s    r<   r   zInMemoryConfig.reloadl  s     #'rL   c           
        | j                   t        | 	  |      S ddlm}m} |j                  d      }| j                  J | j                  j                  d      }|r|s |dt        d       || j                   |||j                  d      | j                  j                  d      |j                  d	      | j                         
      }|j                  | j                         |S )Nr   r  rQ   rN   z%config dict with authentication.type zQ must include 'authentication.federation_rule_id' and top-level 'organization_id'rR   rO   rS   r  )r8  superr  r  r   r-   rD   r   r[   r   r   r   )rd   r^   r   r-   rQ   rN   r#  	__class__s          r<   r  z'InMemoryConfig._build_workload_delegater  s    11973D99Q!XX&:;||''',,**+<=!'78Q7T UV W  /$($J$J1+#xx(<=)).9((7#--/
 	t~~.rL   )r]   rW   r   zOptional[IdentityTokenProvider]ry   r%  rY   rZ   r(  r)  r*  )ro   rp   rq   rr   r   r   r7  rf   r
   r   r   r  __classcell__)r=  s   @r<   r1   r1     s    2 #gll#78O DH.2+A+A "A	+A
 ,+A 
+AZ   ' '
  rL   r1   )r8   r   r9   zOptional[pathlib.Path]rY   zOptional[int])r]   rW   r^   rW   rY   rZ   )J
__future__r   rE   r   r   r   r	  loggingr   r   typingr   r   r   r   r   r	   typing_extensionsr
   r   _typesr   r   _secretsr   r   r   r   r   r   
_constantsr   r   r   r   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   _exceptionsr+   	getLoggerro   r,   __annotations__r  r-   __all__r=   r   CONFIG_FILE_VERSIONr  r[   r\   r`   r.   r/   r0   r2   r1   rs   rL   r<   <module>rK     s    " 	        B B &  6      0 *'g''1^ 16
_" &      . # '>? ?9 9"[	 [	|+ +\m_ mrL   