
    j@              	      `   U d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
  eh d      Zded<    G d d	e      Z eh d
      Zded<    eh d      Zded<   ddZddZ eh d      Zded<   ddZddd	 	 	 	 	 	 	 ddZddZddddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d dZg dZy)!u  anu_v2.ci_gemini_watcher_gh_adapter — task-2719, GET-only gh_runner 어댑터.

설계 원칙:
  - runner (ci_gemini_watcher_runner.py) 는 무수정 import-only.
  - GitHub write 0: 실제 comment, merge, post_review 등 write op 절대 금지.
  - decision-only, dry_run 항상 True 고정.
  - one-way isolation: anu_v2/* 와 표준 라이브러리(json, subprocess) 만 import.
    utils / dispatch / scripts / dashboard 의존성 0.
    )annotationsN)AnyCallableFinalMappingSequence>   reviewsfindings	ci_rollup
diff_pathsactual_headzFinal[frozenset[str]]READ_OPSc                      e Zd ZdZy)GhWriteForbiddenErroru5   write op 또는 비허용 메서드 요청 시 raise.N)__name__
__module____qualname____doc__     T/home/jay/workspace/.worktrees/task-2723-dev2/anu_v2/ci_gemini_watcher_gh_adapter.pyr   r      s    ?r   r   >   editlockclosemergereadycreatedeletereopenreviewunlockcomment_WRITE_SUBCMDS>   -F-f--field--input--raw-field_WRITE_INDUCING_FLAGSc                   t        |       }|D ]3  }t        |      j                         t        v s#t	        d|d|d       t        |      D ]  \  }}t        |      }|dv rM|dz   t        |      k  s't        ||dz            j                         dk7  sJt	        d||dz      d|d      |j                  d      r9|j                  d	d      d   j                         dk7  st	        d|d|d      |j                  d
      st        |      dkD  s|dd j                         dk7  st	        d|d|d       |D ]8  }t        |      }|t        v s|j                  d      s(t	        d|d|d       y)u3  GET-only 보장 — argv **전체**에서 다음을 검사해 GhWriteForbiddenError raise.

    (1) write 서브커맨드 (전역 플래그로 서브커맨드 위치가 밀려도 탐지)
    (2) 비-GET 메서드 — ``-X``/``--method`` 분리·``--method=POST`` 등호·``-XPOST`` 붙여쓰기
    (3) 암묵적 POST 유도 데이터 플래그 — ``-f``/``-F``/``--field``/``--raw-field``/``--input``
        (``gh api`` 는 ``-X`` 없이도 데이터 플래그가 있으면 POST 로 승격)

    defense-in-depth 방어선 — gh_cli 호출 직전 실행.
    z$write subcommand forbidden in argv: z (argv=))-Xz--method   GETznon-GET method forbidden: z	--method==r,      N)z--field=z--raw-field=z--input=z$write-inducing data flag forbidden: )liststrlowerr#   r   	enumeratelenupper
startswithsplitr)   )argv	argv_listtokeni	token_strs        r   _assert_readonly_argvr>   3   s    T
I  u:/'6uiwymSTU  i( 5J	**1us9~%#iA.>*?*E*E*G5*P+01q51A0DGI=XYZ  !!+.sA&q)//1U:+0WYMQRS  !!$'C	NQ,>}""$-+0WYMQRS &  J	--1E1E42
 (6ym79-WXY r   c                    | r| j                         nd}|sy	 t        j                  |      S # t        j                  t        f$ r Y yw xY w)uO   stdout 을 JSON 파싱. 빈 문자열/공백이면 None 반환 (예외 금지). N)stripjsonloadsJSONDecodeError
ValueError)stdoutstrippeds     r   _parse_jsonrH   h   sH    !'v||~RHzz(##  *- s   . A
	A
>   FAILURE	CANCELLED	TIMED_OUTACTION_REQUIREDSTARTUP_FAILURE_FAILURE_CONCLUSIONSc                   | sdddS t        | t              sdddS | D ]N  }t        |t              st        |j	                  d      xs d      j                         }|t        v sIdddc S  | D ]N  }t        |t              st        |j	                  d      xs d      j                         }|sC|dk7  sId	ddc S  d
ddS )u   statusCheckRollup 리스트에서 CI state 도출.

    반환: {"state": "SUCCESS"|"FAILURE"|"PENDING"|"UNKNOWN", "remediable": False}
    UNKNOWNFstate
remediable
conclusionr@   rI   status	COMPLETEDPENDINGSUCCESS)
isinstancer1   dictr2   getr6   rN   )rollupitemrT   rU   s       r   _derive_ci_stater^   |   s    
 "%88fd#"%88 =$%,/526<<>
--&e<<=  =$%TXXh'-2.446f+&e<<= e44r   r@   ownerrepoc                    	
 d	fd	d
	fdd fdd fdd fdd fd
d fdd
fd}|S )u  GET-only gh_runner closure 반환.

    Args:
      gh_cli : `gh <argv...>` 실행 후 stdout(JSON 텍스트) 반환하는 callable.
      owner  : GitHub owner (빈 문자열이면 --repo 플래그 생략).
      repo   : GitHub repo  (빈 문자열이면 --repo 플래그 생략).

    Returns:
      op 5종(actual_head / diff_paths / ci_rollup / reviews / findings)을
      dispatch 하는 gh_runner callable.

    Raises:
      GhWriteForbiddenError: 알 수 없는 op 또는 write op 요청 시.
    c                 "     rr	d  d gS g S )u9   owner/repo 둘 다 있을 때만 --repo 플래그 생성.z--repo/r   r_   s   r   _repo_flagsz-build_readonly_gh_runner.<locals>._repo_flags   s#    Tq/00	r   c                0    ddt        |       g        z   S )u:   gh pr view <pr> [--repo owner/repo] 공통 argv 앞부분.prview)r2   )rg   re   s    r   _pr_base_argvz/build_readonly_gh_runner.<locals>._pr_base_argv   s    fc"g&66r   c                     |       ddgz   }t        |        |      }t        |      }t        |t              syt	        |j                  d      xs d      S )u0   PR HEAD SHA 반환. 실패 시 "" (fail-closed).--json
headRefOidr@   )r>   rH   rY   rZ   r2   r[   )	pr_numberr9   rF   datari   gh_clis       r   _actual_headz.build_readonly_gh_runner.<locals>._actual_head   sX    Y'8\*BBd#6"$%488L)/R00r   c                X    |       ddgz   }t        |        	|      }t        |      }t        |t              sg S |j	                  d      }t        |t
              sg S g }|D ]A  }t        |t              s|j	                  d      }|(|j                  t        |             C |S )u1   PR diff 파일 경로 list 반환. 실패 시 [].rk   filespath)r>   rH   rY   rZ   r[   r1   appendr2   )
rm   r9   rF   rn   rr   resultfrs   ri   ro   s
           r   _diff_pathsz-build_readonly_gh_runner.<locals>._diff_paths   s    Y'8W*==d#6"$%I!%&I 	-A!T"uuV}#MM#d),		-
 r   c                     |       ddgz   }t        |        |      }t        |      }t        |t              sdddS |j	                  d      }t        |      S )u   CI rollup state dict 반환.rk   statusCheckRolluprP   FrQ   )r>   rH   rY   rZ   r[   r^   )rm   r9   rF   rn   r\   ri   ro   s        r   
_ci_rollupz,build_readonly_gh_runner.<locals>._ci_rollup   sb    Y'85H*IId#6"$%&e<<-.''r   c                    t        |       j                         dk7  rt        d|       ddd|g}t        |        |      }t	        |      }t        |t              r|S g S )uJ   GET-only review 목록 반환. method != GET 이면 GhWriteForbiddenError.r.   z&reviews op: non-GET method forbidden: apir,   )r2   r6   r   r>   rH   rY   r1   )methodrs   r9   rF   rn   ro   s        r   _reviewsz*build_readonly_gh_runner.<locals>._reviews   sn    v;%''8
C  tUD)d#6"dD!K	r   c                    xs d}	xs d}d| d| d|  d}ddd	|g}t        |        |      }t        |      }t        |t              r|S g S )
u%   PR 코멘트(findings) 목록 반환.OWNERREPOz/repos/rd   z/pulls/z	/commentsr|   r,   r.   )r>   rH   rY   r1   )
rm   _owner_repors   r9   rF   rn   ro   r`   ra   s
          r   	_findingsz+build_readonly_gh_runner.<locals>._findings   sm    !'&%	{)DtUD)d#6"dD!K	r   c                   | dk(  r |d         S | dk(  r |d         S | dk(  r |d         S | dk(  r) |j                  dd      |j                  dd	            S | d
k(  r |d         S t        d|       )u   op 에 따라 5종 GET-only 동작을 dispatch.

        알 수 없는 op (write op 포함) 은 GhWriteForbiddenError raise.
        r   rm   r   r   r	   r}   r.   rs   r@   r
   zwrite/unknown op forbidden: )r[   r   )opkwargsrp   rz   rw   r   r~   s     r   
_gh_runnerz,build_readonly_gh_runner.<locals>._gh_runner  s    
 { 344vk233f[122?FJJx7FB9OPPVK011#&B2&$IJJr   )return	list[str])rg   intr   r   )rm   r   r   r2   )rm   r   r   r   )rm   r   r   rZ   )r}   r2   rs   r2   r   r1   )rm   r   r   r1   )r   r2   r   r   r   r   r   )ro   r`   ra   r   rp   rz   rw   r   ri   re   r~   s   ``` @@@@@@@r   build_readonly_gh_runnerr      s;    *71&	(K K$ r   c                    t        |        t        j                  dgt        t        |       dddd      }|j
                  dk7  ry|j                  S )uo  실 gh CLI 를 subprocess 로 GET-only 호출하는 read-only one-shot dry-run helper.

    - _assert_readonly_argv 검사 통과 후 gh 프로세스 실행.
    - returncode != 0 이면 "" 반환 (fail-closed).
    - 주의: 이 함수는 단발(one-shot) 호출 전용입니다.
      자동 반복/polling/스케줄 실행 목적으로 사용하지 마세요.
    ghT   F)capture_outputtexttimeoutcheckr   r@   )r>   
subprocessrunmapr2   
returncoderF   )r9   ru   s     r   default_gh_clir     sT     $^^	CF A==r   z	task-2719)ro   r`   ra   task_idowner_proofdedupe_checkerrecord_triggertriagec               b    ddl m} t        ||nt        ||      } || |||||||||	|
d      S )u  GET-only, dry_run=True 고정 단발 실행 진입점.

    gh_cli 가 None 이면 default_gh_cli 사용.
    dry_run 은 항상 True 고정 — 인자로 노출하지 않음 (실 write 0 보장).

    Returns:
      WatchResult (ci_gemini_watcher_runner.WatchResult).
    r   )run_watch_cycle)ro   r`   ra   T)rm   expected_headexpected_files	gh_runnerr`   ra   r   r   r   r   r   dry_run)anu_v2.ci_gemini_watcher_runnerr   r   r   )rm   r   r   ro   r`   ra   r   r   r   r   r   r   	runner_cbs                r   run_one_shot_dry_runr   7  sU    , @(+vI
 #%%% r   )r   r   r   r   r   )r9   Sequence[str]r   None)rF   r2   r   r   )r\   r   r   rZ   )ro   zCallable[[Sequence[str]], str]r`   r2   ra   r2   r   zCallable[..., Any])r9   r   r   r2   )rm   r   r   r2   r   r   ro   z%Callable[[Sequence[str]], str] | Noner`   r2   ra   r2   r   r2   r   zMapping[str, Any] | Noner   r   r   r   r   r   r   r   )r   
__future__r   rB   r   typingr   r   r   r   r   	frozensetr   __annotations__RuntimeErrorr   r#   r)   r>   rH   rN   r^   r   r   r   __all__r   r   r   <module>r      ss   #   : : #,E#
 @L @ )2)%  0950 , 
.j /8O/ + 
5L 	x*x x 	x
 x~< 59,0*** "*
 2* * * * ** * * * 	*br   