
    nai0                    d   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Zddl	m
Z
 ddlmZ 	 ddlmZ ddd
ZddZddZddZddZ	 	 	 d	 	 	 	 	 	 	 	 	 ddZddZdddZedk(  r ej$                   e              yy# e$ r)  edej"                          ej$                  d	       Y zw xY w)u  validate_handoff.py — handoff evidence 검증 CLI + 모듈

사용법:
    ./scripts/validate_handoff.py --task <task-id> [--branch <branch-name>] [--check-head-sha]

종료 코드:
    0   PASS (stdout에 valid JSON 출력)
    1   FAIL (stderr에 사유 list 출력)
    )annotationsN)Path)Any)Draft202012Validatoruv   [validate_handoff] ERROR: 'jsonschema' 패키지가 설치되어 있지 않습니다.
  설치: pip install jsonschemafile   c                    | | S t         j                  j                  d      }|rt        |      S t        t              j                         j                  j                  S )uV   WORKSPACE_ROOT 환경변수 우선, 없으면 스크립트 기준 부모 디렉토리.WORKSPACE_ROOT)osenvirongetr   __file__resolveparent)providedenvs     I/home/jay/workspace/.worktrees/task-2516-dev3/scripts/validate_handoff.py_workspace_rootr   )   sL    
**..)
*C
Cy>!!#**111    c                    |dz  dz  |  dz  S )Nmemoryhandoffsz.json )task_id	workspaces     r   _handoff_pathr   4   s    x*,'%/@@@r   c                    | dz  dz  dz  S )Nr   specszhandoff-schema.jsonr   )r   s    r   _schema_pathr    8   s    x'),AAAr   c                    |D ]n  t        j                   |       r yj                  d      r| j                        r yt        fddD              rT| k(  s| j                  dz         sn y y)u   path 가 patterns 중 하나에 매칭되면 True.

    - fnmatch 기반으로 **, * glob 지원.
    - 디렉토리 prefix 매칭: allowed 패턴이 'tests/handoff/**' 이면
      'tests/handoff/test_x.py' 도 허용.
    T/c              3  &   K   | ]  }|v  
 y wNr   ).0cpatterns     r   	<genexpr>z#_matches_allowed.<locals>.<genexpr>S   s     4A1<4s   )*?F)fnmatchendswith
startswithany)pathpatternsr'   s     @r   _matches_allowedr1   @   sq      ??4)
 C T__W%= 444w$//'C-"@  r   c                8   	 | j                  d      }g }d}d}|j                         D ]  }|j                         }|j	                  d      rd}d})|r|j	                  d      rd}?|r|j	                  d      rd}U|r|j	                  d      rd}k|j	                  d	      r|rd}d}|s|j	                  d
      s|dd j                         j                  d      j                  d      }|s|j                  |        |S # t        $ r g cY S w xY w)u   task md 파일에서 allowed_resources.paths 목록을 파싱한다.

    create_handoff.py의 parse_task_paths 와 동일한 단순 파서.
    실패 시 빈 리스트 반환.
    utf-8encodingFzallowed_resources:Tzpaths:zforbidden_paths:z	commands:z```-r	   N"')	read_textOSError
splitlinesstripr-   append)	task_filecontentallowedin_pathsin_allowed_sectionlinestrippeditems           r   _parse_task_allowed_pathsrF   ^   s:   %%w%7 GH""$ %::<34!%H("5"5h"?H("5"56H"IH("5"5k"BHu%*<!&H++C0AB<%%'--c288=Dt$/%0 N;  	s   D DDc           
     P	   g }t        |      }t        | |      }|j                         s|j                  d|        d|i fS 	 |j	                  d      }t        j                  |      }t        |      }
|
j                         s|j                  d|
        d||fS 	 t        j                  |
j	                  d            }t        |      }t        |j                  |      d	 
      }|rS|D ]I  }dj                  d |j                  D              xs d}|j                  d| d|j                          K d||fS |j                  d      | k7  r'|j                  d|j                  d       d|  d       |;|j                  d      |k7  r'|j                  d|j                  d       d| d       |r||n|j                  d      }|s|j                  d       n	 t!        j"                  dd|gdddt%        |            }|j&                  dk7  r0|j                  d| d|j(                  j+                                 nk|j,                  j+                         }|j                  d d!      }||k(  s:|j/                  |      s)|j/                  |      s|j                  d"| d#| d       |j                  d&g       }|j                  d'g       }|r1|D cg c]  }t3        ||      s| }}|r|j                  d(|        |d)z  d*z  |  d+z  }|j                         r?	 t5        |      }|r1|D cg c]  }t3        ||      s| }}|r|j                  d,|        d.D ]I  }|j                  |      }|t7        |      d/kD  s&|j                  d| d0t7        |       d1| d2       K |rd||fS dg |fS # t        $ r#}	|j                  d|	        d|i fcY d}	~	S d}	~	ww xY w# t        $ r#}	|j                  d|	        d||fcY d}	~	S d}	~	ww xY w# t         j0                  $ r |j                  d$       Y t        $ r}	|j                  d%|	        Y d}	~	d}	~	ww xY wc c}w c c}w # t        $ r}	|j                  d-|	        Y d}	~	6d}	~	ww xY w)3u/  handoff JSON을 다단계 검증한다.

    반환:
        (pass: bool, errors: list[str], handoff_data: dict)
        pass=True이면 errors는 빈 리스트, handoff_data에 파싱된 dict.
        pass=False이면 errors에 실패 사유 리스트, handoff_data는 파싱 성공 시 채워짐.
    u   handoff 파일 없음: Fr3   r4   u   JSON 파싱 실패: Nu   스키마 파일 없음: u   스키마 JSON 파싱 실패: c                ,    t        | j                        S r$   )listr/   )es    r   <lambda>z"validate_handoff.<locals>.<lambda>   s    d166l r   )keyz -> c              3  2   K   | ]  }t        |        y wr$   )str)r%   ps     r   r(   z#validate_handoff.<locals>.<genexpr>   s     "Da3q6"Ds   z(root)u   Schema 위반 [z]: r   u   task_id 불일치: JSON에는 'u   ', 인자는 'r8   current_branchu    current_branch 불일치: JSON='z', --branch='u.   check-head-sha: 검증 대상 branch 미지정gitz	rev-parseT   )capture_outputtexttimeoutcwdr   zcheck-head-sha: git rev-parse 'u   ' 실패 — head_sha u   head_sha 불일치: JSON='z', git rev-parse='u*   check-head-sha: git rev-parse 타임아웃u&   check-head-sha: git 실행 오류 — allowed_pathschanged_pathsu.   changed_paths가 allowed_paths 범위 초과: r   tasksz.mduS   handoff allowed_paths가 task 파일 allowed_resources를 초과 (forgery 의심): u=   task 파일 allowed_resources 파싱 실패 (선택 검증): )pending_workknown_failuresi  u   ' 필드가 4000자 초과 (u   자) — 외부 파일 'u   _path' 사용 필요)r   r   existsr=   r9   jsonloads	Exceptionr    r   sortediter_errorsjoinabsolute_pathmessager   
subprocessrunrN   
returncodestderrr<   stdoutr-   TimeoutExpiredr1   rF   len)r   branchcheck_head_shaworkspace_rooterrorsr   hpathrawdataexcschema_pschema	validatorschema_errorssepath_strcbresult
actual_sharecorded_sharY   rZ   cp
violationsr>   spec_allowedapforgedfieldvals                                 r   validate_handoffr      s    F/I '9-E<<>/w78fb  !oowo/#zz# I&H??1(<=fd""#H...@A
 %V,I9006<RSM 	GB{{"D23C3C"DDPHMMOH:SEF	G fd"" xx	g%-dhhy.A-B.QXPYYZ[	

 88$%/MM2488<L3M2N O#HA' )Vtxx8H/IMMJKN#K,#'I $$)MM9"]!==..013
 "(!4!4!6J#'88J#;L #l2%00>'22:>8 G..8\<  $xx<M#xx<M&
#B6 

 
 MM@M H$w.G9C@I	4Y?L "/+B=   MM--3H6 4 hhuo?s3x$MME76s3xj A""'(<> fd""T>w  !,SE23fb  !  #6se<=fd""#v ,, LJK N FseLMMN
$  	MMOPSuU 	s   'O  %O3 &CP"  Q3,Q= =Q8Q= 	O0O+%O0+O03	P<PPP"$Q0	Q0Q++Q08Q= =	R%R  R%c                     t        j                  dd      } | j                  dddd       | j                  d	d d
d       | j                  ddd       | S )Nr   u<   handoff evidence JSON 다단계 검증 (task-2458 Phase 2-B))progdescriptionz--taskTTASK_IDu   task ID (예: task-2458))requiredmetavarhelpz--branchBRANCHu4   current_branch 값 검증 (예: task/task-2458-dev4))defaultr   r   z--check-head-sha
store_trueu1   head_sha 와 실제 git HEAD 일치 여부 검증)actionr   )argparseArgumentParseradd_argument)rO   s    r   _build_parserr   &  sn    R	A NN8dI2  4NN:tXN  PNN%lK  MHr   c                ,   t               }|j                  |       }t        |j                  |j                  |j
                        \  }}}|r"t        t        j                  |dd             y|D ]   }t        d| t        j                         " y)	N)r   rn   ro   F   )ensure_asciiindentr   zFAIL: r   r	   )r   
parse_argsr   taskrn   ro   printr_   dumpssysrj   )argvparserargsokrq   rt   errs          r   mainr   4  s    _FT"D'		{{**B 
djjE!<=  	3CF3%.szz2	3r   __main__r$   )r   Path | Nonereturnr   )r   rN   r   r   r   r   )r   r   r   r   )r/   rN   r0   	list[str]r   bool)r>   r   r   r   )NFN)
r   rN   rn   z
str | Nonero   r   rp   r   r   ztuple[bool, list[str], dict])r   zargparse.ArgumentParser)r   zlist[str] | Noner   int)__doc__
__future__r   r   r+   r_   r   rg   r   pathlibr   typingr   
jsonschemar   ImportErrorr   rj   exitr   r   r    r1   rF   r   r   r   __name__r   r   r   <module>r      s    #    	  
  /2AB<%\  "&	UUU U  	U
 "Ux* zCHHTV [	  		+ZZ
 CHHQKs   B +B/.B/