
    Ni-%                        d Z ddlmZ ddlZddlZddlZddlmZ dddZdddZ	 G d d      Z
 G d	 d
      Z G d d      Zy)ul  task-2457 Phase 2-A: pre-push hook 테스트.

명세:
  차단 케이스 (exit 1):
    1. main direct push (stdin: "refs/heads/x sha refs/heads/main sha") → "main direct push prohibited"
    2. cancelled marker (memory/events/<task-id>.cancelled 존재) → "task <id> cancelled"
    3. lock 부재 / branch-lock 불일치 → "lock missing" or "task-id mismatch"
    4. scope 위반 (변경 파일이 allowed_resources에 없음) → "scope violation"

  PASS 케이스 (exit 0):
    P3. lock + scope_check PASS + cancelled 아님 + main 아님
    P4. TASKCTL_BYPASS=1 + reason 제공 → bypass evidence 기록 + PASS

  Fallback 케이스:
    - taskctl verify 미존재 → fallback evidence 기록 (verify_status="fallback") + PASS
      파일: .tasks/evidence/<task-id>/verify-fallback-*.json
      필드: taskctl_verify_status / reason / lock_check / scope_check
    )annotationsN)Pathc                   | |z  }|j                   j                  dd       |j                  |d       t        j                  dd|gt        |       dd       t        j                  ddd	d
| dgt        |       dd       y)uM   헬퍼: repo 안에 파일을 만들고 --no-verify 로 commit (hook 우회).T)parentsexist_okutf-8encodinggitadd)cwdcheckcapture_outputcommitz-mzadd z--no-verifyN)parentmkdir
write_text
subprocessrunstr)reporel_pathcontentfs       N/home/jay/workspace/.worktrees/task-2467-dev6/tests/git_hooks/test_pre_push.py_commit_filer      s{    xAHHNN4$N/LL7L+NNE5(+T$W[\NN	$$xj 1=AI	    c           	     ,    d}d}d}d| d| d|  d| d	S )u1   헬퍼: pre-push hook 표준 stdin 라인 생성.task/task-2457-dev3'abc1234abc1234abc1234abc1234abc1234abc1'def5678def5678def5678def5678def5678def5zrefs/heads/ z refs/heads/
 )remote_branchlocalsha_lsha_rs       r   
_stdin_forr)   *   s2    !E5E5Eq|M?!E7"MMr   c                  $    e Zd Zd Zd Zd Zd Zy)TestPrePushFailc                    d} |||        ||d|       t        d      } ||d|      }|j                  dk(  s!J d	|j                  d
|j                         d|j                  v sJ d|j                  v sJ y)u5   1) refspec 의 remote 가 refs/heads/main → 차단.r   	task-2457task_idbranchmain)r%   pre-pushstdin   u*   main direct push 인데 통과됨. stdout= stderr=	[BLOCKED]zmain direct push prohibitedN)r)   
returncodestdoutstderr)selfgit_repocheckout_branch	make_lockrun_hookr0   r4   results           r   test_main_direct_push_blocksz,TestPrePushFail.test_main_direct_push_blocks6   s     '&)(K?0(Je<  A% 	
88IRXR_R_Qbc	
% fmm+++,===r   c                D   d} |||        ||d|        ||d        ||dt                     }|j                  dk(  s!J d|j                  d|j                         d	|j                  v sJ d
|j                  j	                         v sJ d|j                  v sJ y)u&   2) cancelled marker 존재 → 차단.r   r-   r.   r2   r3   r5   u*   cancelled marker 인데 통과됨. stdout=r6   r7   	cancelledNr)   r8   r9   r:   lower)r;   r<   r=   r>   make_cancelledr?   r0   r@   s           r   test_cancelled_marker_blocksz,TestPrePushFail.test_cancelled_marker_blocksE   s     '&)(K?x-(JjlC  A% 	
88IRXR_R_Qbc	
% fmm+++fmm113333fmm+++r   c                8   d} |||        ||dt                     }|j                  dk(  s!J d|j                  d|j                         d|j                  v sJ |j                  j	                         }d|v sd	|v sd
|v sJ d|j                         yyy)u   3) lock 부재 → 차단.r   r2   r3   r5   u$   lock 부재인데 통과됨. stdout=r6   r7   zlock missingztask-id mismatchlocku   lock 관련 메시지 부재: NrD   )r;   r<   r=   r?   r0   r@   msgs          r   test_lock_missing_blocksz(TestPrePushFail.test_lock_missing_blocksZ   s     '&)(JjlC  A% 	
26==2C8FMMK\]	
% fmm+++mm!!##%+=+D&TW- 	
,V]],=>	
X-+D%r   c                D   d} |||        ||d|        ||ddg       t        |dd        ||dt               	      }|j                  d
k(  s!J d|j                  d|j                         d|j                  v sJ d|j                  j                         v sJ y)uH   4) capability 의 allowed_resources 에 없는 파일 변경 → 차단.r   r-   r.   tests/git_hooks/allowed_pathszscripts/forbidden.pyzprint('out of scope')
r2   r3   r5   u%   scope 위반인데 통과됨. stdout=r6   r7   zscope violationN)r   r)   r8   r9   r:   rE   r;   r<   r=   r>   make_capabilityr?   r0   r@   s           r   test_scope_violation_blocksz+TestPrePushFail.test_scope_violation_blocksk   s     '&)(K?-.	
 	X57PQ(JjlC  A% 	
3FMM3DHV]]L]^	
% fmm+++ FMM$7$7$9999r   N)__name__
__module____qualname__rA   rG   rK   rR   r$   r   r   r+   r+   5   s    >,*
":r   r+   c                      e Zd Zd Zd Zy)TestPrePushPassc                    d} |||        ||d|        ||dddg       t        |dd        ||d	t               
      }|j                  dk(  s!J d|j                  d|j                         y)uB   P3) lock + scope PASS + cancelled 아님 + main 아님 → exit 0.r   r-   r.   rM   zscripts/git-hooks/rN   ztests/git_hooks/sample.txtok
r2   r3   r   u)   정상 케이스인데 차단됨. stdout=r6   N)r   r)   r8   r9   r:   rP   s           r   test_valid_lock_scope_passesz,TestPrePushPass.test_valid_lock_scope_passes   s     '&)(K?-/CD	
 	X;VD(JjlC  A% 	
77HQWQ^Q^Pab	
%r   c                   d} |||       ddd} ||dt               |      }|j                  dk(  s!J d|j                  d	|j                         |d
z  dz  dz  }|j	                         sJ d       t        |j                  d            }|s!J dt        |j                                       t        j                  |d   j                  d            }	|	j                  d      du sJ |	j                  d      sJ |	j                  d      t        j                  j                  d      k(  sJ |	j                  d      dk(  sJ y)u9   P4) TASKCTL_BYPASS=1 + reason → PASS + evidence 기록.r   1z"emergency push for outage rollback)TASKCTL_BYPASSTASKCTL_BYPASS_REASONr2   )r4   	env_extrar   u"   bypass push 통과 못함. stdout=r6   .tasksevidencer-      evidence 디렉토리 미생성zbypass-*.jsonu   bypass-*.json 부재. 내용=r   r	   bypassT	timestampactorUSERreasonN)r)   r8   r9   r:   is_dirlistglobiterdirjsonloads	read_textgetosenviron)
r;   r<   r=   r?   r0   envr@   evidence_dirbypass_filesdatas
             r   2test_bypass_with_reason_passes_and_writes_evidencezBTestPrePushPass.test_bypass_with_reason_passes_and_writes_evidence   sU    '&)!%I
 (JjlcR  A% 	
00A&--IZ[	
%  (*Z7+E""$G&GG$L--o>?[<T,BVBVBX=Y<Z[[|zz,q/33W3EFxx!T)))xx$$$xx BJJNN6$::::xx!%IIIIr   N)rS   rT   rU   rZ   rv   r$   r   r   rW   rW      s    
0Jr   rW   c                      e Zd Zd Zy)TestPrePushFallbackc                   d} |||        ||d|        ||ddg       t        |dd       |dz  d	z  }|j                         rJ d
        ||dt                     }|j                  dk(  s!J d|j                  d|j
                         |dz  dz  dz  }	|	j                         sJ d       t        |	j                  d            }
|
s!J dt        |	j                                       t        j                  |
d   j                  d            }|j                  d      dk(  s
J d|        |j                  d      s
J d|        |j                  d      dk(  s
J d|        |j                  d      dk(  s
J d |        y!)"u   taskctl verify 가 사용 불가 → fallback evidence 기록 + PASS.

        - 파일: .tasks/evidence/<task-id>/verify-fallback-*.json
        - 필드: taskctl_verify_status="fallback", reason, lock_check="PASS", scope_check="PASS"
        r   r-   r.   rM   rN   ztests/git_hooks/in_scope.txtrY   scriptsztaskctl_verify.pyu*   테스트 전제: taskctl_verify.py 부재r2   r3   r   u   fallback 통과 못함. stdout=r6   r`   ra   rb   zverify-fallback-*.jsonu&   verify-fallback-*.json 부재. 내용=r   r	   taskctl_verify_statusfallbackz#taskctl_verify_status != fallback: rg   u   reason 누락: 
lock_checkPASSzlock_check != PASS: scope_checkzscope_check != PASS: N)r   existsr)   r8   r9   r:   rh   ri   rj   rk   rl   rm   rn   ro   )r;   r<   r=   r>   rQ   r?   r0   verify_scriptr@   rs   fallback_filesru   s               r   2test_taskctl_verify_missing_uses_fallback_evidencezFTestPrePushFallback.test_taskctl_verify_missing_uses_fallback_evidence   s    '&)(K?-.	

 	X=vF !9,/BB '')W+WW)(JjlC  A% 	
-fmm->hv}}FWX	
%  (*Z7+E""$G&GG$l//0HIJ 	
4T,:N:N:P5Q4RS	
~ zz.+55w5GHxx/0J> 	
1$8	
> xx!;_TF#;;!xx%/N3Gv1NN/xx&&0P4I$2PP0r   N)rS   rT   rU   r   r$   r   r   rx   rx      s    .Qr   rx   )x)r   r   r   r   r   r   returnNone)r   )r%   r   r   r   )__doc__
__future__r   rl   rp   r   pathlibr   r   r)   r+   rW   rx   r$   r   r   <module>r      sL   & #  	  NO: O:j1J 1Jn/Q /Qr   