
    (<i(                        U d Z 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m	Z	 ddl
ZddlZ ej                  d      ZdZdZdZddd	Zd
ed<   efddZdddZ	 d	 	 	 ddZddZddZddZddZy)u  gcloud 인증 영구화 모듈.

Application Default Credentials(ADC)를 우선 시도하고,
실패 시 gcloud CLI fallback으로 토큰을 획득합니다.
토큰 캐싱 및 만료 5분 전 자동 갱신을 지원합니다.

추가 지원:
- API 키 인증: get_api_key()로 .env / .env.keys에서 GEMINI_API_KEY 로드
- SA 경로 설정: .env.keys의 GEMINI_SA_PATH 환경변수 로드
- SA 직접 토큰 획득: get_service_account_token(scope)
    )annotationsN)Anygcloud_authi,  z/home/jay/workspace/.env.keysz/home/jay/workspace/.env)tokenexpiryzdict[str, Any]_token_cachec                l   | }t         j                  j                  |      st        j	                  d|       y	 t        |d      5 }|j                         }ddd       t        j                  dt        j                        }ddh}|j                        D ]a  }|j                  d	      }|j                  d
      j                         }	||v s8|	t         j                  |<   t        j	                  d||	       c y# 1 sw Y   xY w# t        $ r }t        j                  d|       Y d}~yd}~ww xY w)u[  지정된 .env.keys 파일에서 환경변수를 로드합니다.

    GOOGLE_APPLICATION_CREDENTIALS 등 Google 인증 관련 변수를 파싱하여
    현재 프로세스 환경에 설정합니다. 파일이 없으면 조용히 무시합니다.

    Args:
        env_path: .env.keys 파일 경로. 기본값은 프로젝트 표준 경로.
    u,   env.keys 파일이 없습니다: %s (무시)Nutf-8encodingu!   env.keys 파일 읽기 실패: %sz7^\s*export\s+([A-Z_][A-Z0-9_]*)\s*=\s*"?([^"\n]*)"?\s*$GOOGLE_APPLICATION_CREDENTIALSGEMINI_SA_PATH      u   환경변수 설정: %s=%s)ospathexistsloggerdebugopenreadOSErrorwarningrecompile	MULTILINEfinditergroupstripenviron)
env_pathr   fcontentepattern_ENV_KEYS_ALLOWLISTmatchkeyvalues
             O/home/jay/workspace/.worktrees/task-2057-dev2/tools/ai-image-gen/gcloud_auth.pyload_env_keysr+   )   s    D77>>$CTJ$) 	QffhG	 jjB
G <=MN!!'* Ckk!nA$$&%%#BJJsOLL5sEBC	 	 :A>s/   D
 C>D
 >DD
 
	D3D..D3c                H    t         j                  j                         }|rt        j	                  d        |S d fd} |t
              }|rt        j	                  d        |S  |t              }|rt        j	                  d        |S t        j	                  d        y)u]  .env 및 .env.keys 파일에서 API 키를 로드하여 반환합니다.

    탐색 순서:
    1. 현재 환경변수 (os.environ)
    2. .env 파일 (GEMINI_API_KEY 등)
    3. .env.keys 파일

    Args:
        key_name: 로드할 환경변수 이름. 기본값은 "GEMINI_API_KEY".

    Returns:
        API 키 문자열, 없으면 None.
    u   환경변수에서 %s 로드c                   t         j                  j                  |       sy 	 t        | d      5 }|j	                         }d d d        t        j                  dt        j                        z   dz   t        j                        }|j                        }|r|j                  d      j                         S y # 1 sw Y   yxY w# t
        $ r Y y w xY w)Nr
   r   z^\s*(?:export\s+)?z\s*=\s*"?([^"\n]+)"?\s*$r   )r   r   r   r   r   r   r   r   escaper   searchr   r   )r   r"   r#   r%   r'   key_names        r*   _parse_filez get_api_key.<locals>._parse_filea   s    ww~~d#	dW- #&&(# **!BIIh$77:UULL
 w';;q>''))# # 		s(   C B9C 9C>C 	CCu   .env 파일에서 %s 로드u    .env.keys 파일에서 %s 로드u   %s 를 찾을 수 없습니다.N)r   strreturn
str | None)r   r    getr   r   _DEFAULT_ENV_PATH_DEFAULT_ENV_KEYS_PATH)r0   r)   r1   vals   `   r*   get_api_keyr9   L   s     JJNN8$E3X>$ '
(C
2H=
 ,
-C
7B

LL2H=    c                   ddl }t        t               t        j                  j                  d      xs t        j                  j                  d      }|st        d      t        j                  j                  |      st        d|       t        j                  d||        	 |j                  j                  j                  j                  || g      }|j                  j                   j"                  j%                         }|j'                  |       |j*                  }|st        d      t        j                  dt-        |             |S # t(        $ r}t        d	| d
|       |d}~ww xY w)u  서비스 계정(SA) 키 파일로 액세스 토큰을 직접 생성하여 반환합니다.

    SA 경로 탐색 순서:
    1. GEMINI_SA_PATH 환경변수 (또는 .env.keys에서 로드)
    2. GOOGLE_APPLICATION_CREDENTIALS 환경변수

    Args:
        scope: 요청할 OAuth2 scope URL.
               기본값: "https://www.googleapis.com/auth/generative-language"

    Returns:
        유효한 Bearer 토큰 문자열.

    Raises:
        RuntimeError: SA 경로를 찾을 수 없거나 토큰 생성에 실패한 경우.
    r   Nr   r   u|   서비스 계정 경로를 찾을 수 없습니다. GEMINI_SA_PATH 또는 GOOGLE_APPLICATION_CREDENTIALS를 설정하세요.u6   서비스 계정 파일이 존재하지 않습니다: u2   SA 키 파일로 토큰 생성 중: %s (scope: %s))scopesu'   서비스 계정 토큰 생성 실패 (z): u/   서비스 계정 토큰이 비어 있습니다.u*   SA 토큰 생성 완료 (길이: %d chars))google.oauth2.service_accountr+   r7   r   r    r5   RuntimeErrorr   r   r   infooauth2service_accountCredentialsfrom_service_account_fileauth	transportrequestsRequestrefresh	Exceptionr   len)scopegooglesa_pathcredentialsrequestr$   r   s          r*   get_service_account_tokenrP      sN   & ) ()jjnn-.b"**..Aa2bG N
 	
 77>>'"ST[S\]^^
KKDguU]mm33??YY7 Z 
 ++''0088:G$ ""ELMM
KK<c%jIL  ]DWISQRPSTU[\\]s   &A1E 	E1E,,E1c                 p    t         d   } t         d   }| |y|t        j                         z
  }|t        kD  S )uJ   캐시된 토큰이 유효하고 5분 이상 남았는지 확인합니다.r   r   F)r   time_RENEWAL_THRESHOLD_SECS)r   r   	remainings      r*   _is_cache_validrU      s>    !E(#F}$I...r:   c                 N   t         j                  j                         \  } }| j                  sZt         j                  j                  j
                  j                         }| j                  |       t        j                  d|       nt        j                  d|       | j                  }t        | d      rF| j                  :| j                  }|j                  |j                         }n(|j                         }nt        j                         dz   }|t         d<   |t         d<   |S )u   Application Default Credentials로 토큰을 획득합니다.

    Returns:
        유효한 액세스 토큰 문자열.

    Raises:
        Exception: ADC 초기화 또는 refresh 실패 시.
    u+   ADC 토큰 갱신 완료 (프로젝트: %s)u+   ADC 토큰 획득 완료 (프로젝트: %s)r   i  r   )rL   rD   defaultvalidrE   rF   rG   rH   r   r?   r   hasattrr   tzinfo	timestamprR   r   )rN   projectrO   r   	expiry_dt	expiry_tss         r*   _try_adcr_      s     ";;..0K ++''0088:G$A7KA7K""E {H%+*<*<*H&&	#!++-I!++-IIIK$&	!L&LLr:   c                 0   t         j                  d       t        j                  g dddd      } | j                  j                         }|st        d      t         j                  d       t        j                         dz   }|t        d<   |t        d	<   |S )
u   gcloud CLI를 통해 access token을 획득합니다 (fallback).

    Returns:
        유효한 액세스 토큰 문자열.

    Raises:
        RuntimeError: 빈 토큰 반환 시.
        Exception: subprocess 실행 실패 시.
    u5   gcloud CLI fallback으로 토큰 획득 시도 중...)gcloudrD   zprint-access-tokenT)capture_outputtextcheckuC   gcloud auth print-access-token이 빈 토큰을 반환했습니다.u(   gcloud CLI fallback 토큰 획득 완료i  r   r   )	r   r?   
subprocessrunstdoutr   r>   rR   r   )resultr   r^   s      r*   _try_gcloud_cliri      s     KKGH^^0	F MM!E`aa
KK:; 		g%I!L&LLr:   c                    t               r;t        j                  dt        d   t	        j                         z
         t        d   S t
        j                  j                  d      s.t
        j                  j                  d      st        t               t
        j                  j                  d      xs t
        j                  j                  d      } | r	 t               }|S 	 t               }|S # t        $ r }t        j                  d|       Y d}~1d}~ww xY w# t        $ r }t        j                  d|       Y d}~nd}~ww xY w	 t               }|S # t        $ r  t        $ r}t        d	|       |d}~ww xY w)
u  유효한 Google Cloud access token을 반환합니다.

    캐시에 유효한 토큰(만료 5분 이상 남음)이 있으면 그대로 반환합니다.
    그렇지 않으면:
    1. ADC(Application Default Credentials) 우선 시도
    2. ADC 실패 시 gcloud CLI fallback

    .env.keys에서 GOOGLE_APPLICATION_CREDENTIALS를 자동으로 로드합니다.

    Returns:
        유효한 Bearer 토큰 문자열.

    Raises:
        RuntimeError: 모든 인증 방법이 실패한 경우.
    u)   캐시된 토큰 반환 (잔여: %.0f초)r   r   r   r   u7   SA 토큰 획득 실패: %s. ADC fallback 시도 중...Nu?   ADC 토큰 획득 실패: %s. gcloud CLI fallback 시도 중...u<   gcloud 인증 실패 — SA, ADC, gcloud CLI 모두 실패: )rU   r   r   r   rR   r   r    r5   r+   r7   rP   rI   r   r_   ri   r>   )rM   r   sa_erradc_errcli_errs        r*   get_access_tokenrn   	  sK   " @,xBX[_[d[d[fBfgG$$ ::>>:;BJJNNScDd,- jjnn-.b"**..Aa2bG	-/EL

  	NNI 	  
M	
 	

r!  rYZaYbcdjqqrsH   C/ #D /	D8DD	E$D??EE E:&E55E:)r!   r2   r3   None)GEMINI_API_KEY)r0   r2   r3   r4   )z3https://www.googleapis.com/auth/generative-language)rK   r2   r3   r2   )r3   bool)r3   r2   )__doc__
__future__r   loggingr   r   re   rR   typingr   google.authrL   google.auth.transport.requests	getLoggerr   rS   r7   r6   r   __annotations__r+   r9   rP   rU   r_   ri   rn    r:   r*   <module>r{      s   
 #  	 	     %			=	)   9 .   n  #9  CF3n G222j	/$N>6rr:   