
    9bj7                       d Z ddlmZ ddlZddlmc m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 ed      Zedz  dz  Zddd	 	 	 dd	Zej&                  d
        ZddZd Zd Zd Zd Zd Zd Zd ZdddZd Zd Zd Z d Z!d Z"d Z#y)u  tests/test_taskctl.py — taskctl MVP 회귀 테스트 (task-2449)

8가지 케이스 + bypass:
    정상 (3):
        1. test_normal_verify_runs_and_collects_evidence
        2. test_normal_approve_transitions_to_human_approved
        3. test_normal_merge_dry_run_completes
    차단 (5):
        4. test_blocked_cancelled_task_merge_exits_1
        5. test_blocked_main_direct_push_via_pre_push_hook_exits_1
        6. test_blocked_no_direct_gh_pr_merge_in_codebase  (grep 검증)
        7. test_blocked_guard_sh_fail_blocks_merge
        8. test_blocked_human_approval_missing_blocks_merge
    bypass (1):
        9. test_bypass_records_evidence_and_proceeds
    구조 검증:
        10. test_help_lists_all_subcommands
        11. test_state_file_checksum_detects_tampering
    )annotationsN)Pathz/home/jay/workspacescriptsz
taskctl.py)envcwdc                    t         j                  j                         }| r|j                  |        t	        j
                  t        j                  t        t              g|ddd|t        |xs t                    S )NT<   )capture_outputtexttimeoutr   r   )osenvironcopyupdate
subprocessrunsys
executablestrTASKCTL	WORKSPACE)r   r   argsbase_envs       C/home/jay/workspace/.worktrees/task-2696-dev7/tests/test_taskctl.py_run_taskctlr   '   s]    zz H
>>	W--$#c.Y/     c                &   | dz  }|j                          |dz  dz  j                  d       |dz  j                  t        dz         |dz  j                  d       |dz  d	z  j                  d       |j                  d
t	        |             |S )uB   별도 .tasks/state 디렉토리로 실행되는 격리된 환경.fake_workspace.tasksstateT)parentsr   memoryexist_okeventsWORKSPACE_ROOT)mkdir
symlink_tor   setenvr   )tmp_pathmonkeypatchr   s      r   isolated_stater,   3   s      00Nh(///=i++I	,ABh%%t%4h)00$0?'^)<=r   c                    | dz  dz  | dz  S )Nr   r    .json )	workspacetask_ids     r   _state_filer2   @   s    x')wiu,===r   c                 J   t        j                  t        j                  ddt	        t
              gddd      } | j                  }d}||k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |       rt        j                  |       nd	t        j                  |      t        j                  |      d
z  }t        j                  d| j                         dz   d|iz  }t        t        j                   |            d x}x}}y )N-m
py_compileT   )r
   r   r   r   ==z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sprocpy0py2py5zpy_compile FAIL: 
>assert %(py7)spy7)r   r   r   r   r   r   
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstderrAssertionError_format_explanation)r:   @py_assert1@py_assert4@py_assert3@py_format6@py_format8s         r   test_taskctl_py_compilerQ   I   s    >>	|S\:$D ??BaB?aBBB?aBBBBBB4BBB4BBB?BBBaBBB#4T[[M!BBBBBBBBr   c                    t        d      } | j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}| j                  }d	D ]  }||v }|st        j                  d
|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  |      rt        j                  |      nddz  }t        j                  d| d      dz   d|iz  }	t        t        j                  |	            d } y )Nz--helpr   r7   r9   r:   r;   assert %(py7)sr@   )initdispatchackr   pr-openverifyapprovemergecancelfailstatusin)z%(py0)s in %(py2)scmdout)r<   r=   u   --help 출력에 'u   ' 누락z
>assert %(py4)spy4)r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   stdoutrH   )
r:   rL   rM   rN   rO   rP   ra   r`   @py_format3@py_format5s
             r   test_help_lists_all_subcommandsrf   Q   s   !D??a?a?a44?a
++C@ >cz===sc======s===s======c===c====/uH=======>r   c                	   d}t        d|      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}t        | |      }|j                  } |       }|sd
dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            d x}}t        j                  |j                               }
d|
d<   |j                  t        j                   |
             t        d|      }|j                  }d}||k7  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}g }d}|j"                  }|j$                  } |       }||v }|}|s'd}|j"                  }|j$                  } |       }||v }|}|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }|j'                  |       |st        j                  dfdf      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                        t        j                        t        j                  |      dz  }dd|iz  }|j'                  |       t        j(                  |d      i z  }dd|iz  }t        t        j                  |            d x}x}x}x}x}x}x}x}x}x}x}}y ) Nztask-tamper-99rT   r   r7   r9   r:   r;   rS   r@   Aassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}pr<   r=   rb   HUMAN_APPROVEDcurrent_stater]   !=z2%(py2)s
{%(py2)s = %(py0)s.returncode
} != %(py5)schecksumtamperedr^   )zb%(py3)s in %(py11)s
{%(py11)s = %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s.stderr
}.lower
}()
})py3r>   r@   py9py11z%(py13)spy13)zh%(py16)s in %(py24)s
{%(py24)s = %(py22)s
{%(py22)s = %(py20)s
{%(py20)s = %(py18)s.stderr
}.lower
}()
})py16py18py20py22py24z%(py26)spy26   zassert %(py29)spy29)r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   r2   existsjsonloads	read_text
write_textdumpsrI   lowerappend_format_boolop)r,   r1   r:   rL   rM   rN   rO   rP   ri   re   data@py_assert2@py_assert6@py_assert8@py_assert10@py_assert0@py_assert15@py_assert19@py_assert21@py_assert23@py_assert17@py_format12@py_format14@py_format25@py_format27@py_format28@py_format30s                              r   *test_state_file_checksum_detects_tamperingr   Z   s   G(D??a?a?a44?aNG,A888::118:::akkm$D,DLLD!"'*D??a?a?a44?aQ:QQ**Q*,Q:,,Q
QdkkQk>O>OQ>O>QQ
>Q0QQQQQ:,QQQ:QQQQQQQQQQQQQQQ*QQQ,QQQQQQQ
>QQQQ
QQQQQQdQQQdQQQkQQQ>OQQQ>QQQQQQQQQQQQQQQQr   c                   d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}d}d}d}t        ||||      }|j                  }	d}
|	|
k(  }|sFt        j                  d|fd|	|
f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}	x}}
t        d|d       t        j                  t        | |      j                               }|d   }|d   }ddh}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}|d!   }ddh}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}d}|d"   }||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}|d#   }d$d%h}||v }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}|d&   }d'}||k(  }|slt        j                  d|fd(||f      t        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}}y))u  정상 1: verify 명령이 evidence를 수집하고 state 파일을 갱신한다.

    fake workspace는 git repo도 PR도 없으므로 guard.sh / qc_report_guard 모두
    FAIL이 예상된다. 핵심 검증 항목:
        - evidence.guard_sh_result / qc_report_guard_result 필드 존재
        - evidence.exit_codes['verify'] 기록
        - PR_OPEN 또는 GUARD_PASS 상태 유지 (terminal로 빠지지 않음)
    ztask-2449-normal-1rT   r   r7   zZ%(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}.returncode
} == %(py10)sr   r1   r<   r=   rr   r>   r@   py10assert %(py12)spy12NrU   rV   r   rW   --pr999zn%(py11)s
{%(py11)s = %(py9)s
{%(py9)s = %(py0)s(%(py2)s, %(py3)s, %(py5)s, %(py7)s)
}.returncode
} == %(py14)sr<   r=   rr   r>   r@   rs   rt   py14assert %(py16)srv   rX   z	--machineevidenceguard_sh_resultPASSFAILr^   )z%(py1)s in %(py4)spy1rb   assert %(py6)spy6qc_report_guard_result
exit_codesrl   
GUARD_PASSPR_OPEN	pr_numberi  z%(py1)s == %(py4)sr   rA   rB   rC   rD   rE   rF   rG   rJ   rK   r   r   r2   r   )r,   r1   rL   rM   r   @py_assert9r   @py_format11@py_format13r   @py_assert13@py_assert12@py_format15@py_format17r    evr   rN   r   re   @py_format7s                        r   -test_normal_verify_runs_and_collects_evidencer   m   s    #G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888"<<
G,<,77<1<71<<<<71<<<<<<<<<<<<<<
<<<<<<G<<<G<<<,<<<7<<<1<<<<<<<7<w'7'227a72a77772a777777<777<777777777w777w777'7772777a77777777<w'7'227a72a77772a777777<777<777777777w777w777'7772777a7777777!JFJEJ<	7FE:J:EEJJEJJJJEJJJJJJ<JJJ<JJJ	JJJJJJ7JJJ7JJJFJJJEJJJ:JJJEJJJJJJJJJJJ7K0JJ{>7;EEGHE	z	B 4VV$44 $44444 $4444 444$44444444&';FF+;;'+;;;;;'+;;;;';;;+;;;;;;;;'r,''8'''''8''''8'''''''''''!>lI%>>!%>>>>>!%>>>>!>>>%>>>>>>>>k?!c!?c!!!!?c!!!?!!!c!!!!!!!r   c                2   d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}dD ]x  }	t        |	|      }
|
j                  }d}||k(  }|sKt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  |	      rt        j                  |	      nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}}{ d}d}d}t        ||||      }|j                  }d}||k(  }|sFt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}}t        | |      }|j                  } |       }
|
sddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }t        t        j                  |            dx}}
t        d|      }|j                  }d}||k7  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d z  }d!d"|iz  }t        t        j                  |            dx}x}
}d#}|j                  }||v }|st        j                  d$|fd%||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      d&z  }d!d"|iz  }t        t        j                  |            dx}x}}y)'u   정상 2: PR_OPEN 상태에서 approve 시도 → 차단 (GUARD_PASS 필요).

    MVP에서는 verify 외 GUARD_PASS 진입 경로가 없으므로,
    PR_OPEN→approve는 차단되어야 한다는 점을 검증한다.
    ztask-2449-normal-2rT   r   r7   r   r   r1   r   r   r   NrU   rV   r   zY%(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}.returncode
} == %(py9)sr`   r<   r   r=   rb   r   rs   assert %(py11)srt   rW   r   1r   r   r   rv   rh   
state_pathrj   rY   rm   ro   r:   r;   rS   r@   r   r^   z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stderr
}r   rr   r>   )r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   r2   r~   rI   )r,   r1   rL   rM   r   r   r   r   r   r`   rN   @py_assert5@py_assert7@py_format10r   r   r   r   r   r   r   re   r:   rO   rP   r   r   s                              r   1test_normal_approve_transitions_to_human_approvedr      s    #G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888) :C)9)4499499994999999|999|999999C999C999999999999)99949999999999:!HFHCH<	7FC8H8CCHqHCqHHHHCqHHHHHH<HHH<HHH	HHHHHH7HHH7HHHFHHHCHHH8HHHCHHHqHHHHHHHH^W5J::	7+D??a?a?a44?a&4;;&<;&&&&<;&&&<&&&&&&4&&&4&&&;&&&&&&&r   c                D
   ~ d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}dD ]x  }	t        |	|      }
|
j                  }d}||k(  }|sKt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  |	      rt        j                  |	      nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}}{ d}d}d}t        ||||      }|j                  }d}||k(  }|sFt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}}t        d|d      }|j                  }d}||k7  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}
}y)!u;  정상 3: HUMAN_APPROVED 상태에서 merge --dry-run → MERGED → DONE.

    taskctl 자체로 GUARD_PASS 전이는 verify를 거쳐야 하므로,
    monkeypatch로 guard.sh / qc_report_guard 호출을 우회하는 헬퍼 사용.
    여기서는 단계별 명령이 정상 동작하는지만 확인한다.
    ztask-2449-normal-3rT   r   r7   r   r   r1   r   r   r   Nr   r   r`   r   r   rt   rW   r   r   r   r   r   rv   rZ   	--dry-runrm   ro   r:   r;   rS   r@   )
r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   )r,   r1   rL   rM   r   r   r   r   r   r`   rN   r   r   r   r   r   r   r   r   r   r:   rO   rP   s                          r   #test_normal_merge_dry_run_completesr      s    	"G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888) :C)9)4499499994999999|999|999999C999C999999999999)99949999999999:!HFHCH<	7FC8H8CCHqHCqHHHHCqHHHHHH<HHH<HHH	HHHHHH7HHH7HHHFHHHCHHH8HHHCHHHqHHHHHHHH+6D??a?a?a44?ar   c           	     <   d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}t        d|d      }	|	j                  }d}||k(  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |	      rt        j                  |	      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}
}t        j                  t        | |      j                               }|d   }d}
||
k(  }|slt        j                  d|fd||
f      t        j                  |      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
y)u0   차단 4: CANCELLED state task → merge exit 1.ztask-2449-block-4rT   r   r7   r   r   r1   r   r   r   Nr[   rZ   r   r|   r9   r:   r;   rS   r@   rl   	CANCELLEDr   r   r   r   r   )r,   r1   rL   rM   r   r   r   r   r   r:   rN   rO   rP   r    r   r   re   r   s                     r   )test_blocked_cancelled_task_merge_exits_1r      sf   !G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888 :<'*:*55::5::::5::::::<:::<:::::::::':::':::*:::5::::::::::+6D??a?a?a44?aJJ{>7;EEGHE!0[0![0000![000!000[0000000r   c                   | j                  d       t        j                  ddd|gt        |       dd       t        j                  g dt        |       dd       t        j                  g d	t        |       dd       | d
z  j	                  d       t        j                  g dt        |       dd       t        j                  g dt        |       dd       y)uE   git init + dummy commit (HEAD가 존재해야 hook이 정상 평가).Tr#   gitrT   z-b)r   r
   check)r   configz
user.emailz
test@local)r   r   r
   )r   r   z	user.nametestREADMEztest
)r   add.)r   commitr4   rT   z--no-verifyN)r'   r   r   r   r   )pathbranchs     r   _init_fake_repor      s    JJJNNE640c$i"&d4 NN@4yTCNN94yTC	H_  *NN&CI"&d4NNA4yTCr   c                T   t         dz  dz  dz  }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}| dz  }t        |d	
       t        j                  dt        |      gt        |      dddd      }|j                  }d}||k(  }|st	        j                  d|fd||f      dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t	        j                  d|j                          dz   d|iz  }	t        t	        j                  |	            dx}x}}d}
|j                   }|
|v }|st	        j                  d|fd|
|f      t	        j                  |
      dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            dx}
x}}y)u   차단 5: pre-push hook 호출 시 main 브랜치 → exit 1.

    실제 git push 환경 시뮬레이션이 아닌, pre-push 스크립트 직접 호출.
    r   	git-hookspre-pushrh   hookrj   N	fake_repomainr   bash T   r   inputr
   r   r   r|   r7   r9   r:   r;   u    main direct push 거부 실패: r?   r@   main direct push prohibitedr^   r   r   rS   )r   r~   rD   rE   rB   rF   rG   rJ   rK   r   r   r   r   rA   rC   rH   rI   )r*   r   rL   rN   re   r   r:   rM   rO   rP   r   r   s               r   7test_blocked_main_direct_push_via_pre_push_hook_exits_1r      s   
 y ;.;D;;;==44;=;&IIf->>	T	N$	D ??QaQ?aQQQ?aQQQQQQ4QQQ4QQQ?QQQaQQQ#CDKK=!QQQQQQQQ(7DKK7(K7777(K777(777777D777D777K7777777r   c                   
 t        j                  g dt        t              ddd      } | j                  dk(  ry| j
                  j                         }g }d}d}d	}|D ]  }|j                  d
d      }t        |      dk\  r|d   n|t        |      dk\  r|d   nd
t        fd|D              rTj                  |      rft        
fd|D              s{|j                  |        | }|s~t        j                  d|       dz   ddt        j                         v st        j                   |      rt        j"                  |      ndiz  }	t%        t        j&                  |	            d}y)u   차단 6: 코드베이스에 'gh pr merge' 직접 호출이 0건.

    예외:
        - scripts/taskctl.py 자체 (유일한 머지 진입점)
        - tests/ (본 파일 등 검증 코드)
        - memory/, dispatch/, *.md (문서)
    )r   grepz-nzgh pr mergeTr6   )r   r
   r   r   r|   N)zscripts/taskctl.pyztests/zmemory/z	dispatch/zscripts/anu_confirm_bot/zscripts/lock_in_verify.pyz.github/workflows/)z.mdz.txtz.logz.jsonlr.   z.ymlz.yaml)zsubprocess.z_run(z_run([z"gh", "pr", "merge"z'gh', 'pr', 'merge':   r      r   c              3  @   K   | ]  }j                  |        y wN)
startswith).0ri   r   s     r   	<genexpr>zAtest_blocked_no_direct_gh_pr_merge_in_codebase.<locals>.<genexpr>  s     <atq!<s   c              3  &   K   | ]  }|v  
 y wr   r/   )r   markercontents     r   r   zAtest_blocked_no_direct_gh_pr_merge_in_codebase.<locals>.<genexpr>	  s     E6W$Es   u2   'gh pr merge' 직접 호출 발견 (taskctl 외): z
>assert not %(py0)sr<   
violations)r   r   r   r   rA   rc   
splitlinessplitlenanyendswithr   rB   rH   rD   rE   rF   rG   rJ   rK   )r:   linesr   allowed_prefixesallowed_extcode_call_markerslnpartsrL   @py_format2r   r   s             @@r   .test_blocked_no_direct_gh_pr_merge_in_codebaser     sc    >>,	N$D !KK""$EJ NK o a u:?uQx!%jAo%(2<+;<<==%E3DEE" > >   =ZLI              r   c                   ~ d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}dD ]x  }	t        |	|      }
|
j                  }d}||k(  }|sKt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  |	      rt        j                  |	      nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}}{ d}d}d}t        ||||      }|j                  }d}||k(  }|sFt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}}t        d|d      }|j                  }d}||k(  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd |iz  }t        t        j                  |            dx}x}
}g }d!}|j                  }||v }|}|s=d"}|j                  }||v }|}|s'd#}|j                  }|j                  } |       }||v }|}|sKt        j                  d$|fd%||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      d&z  }d'd(|iz  }|j                  |       |sjt        j                  d$|fd)f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      d*z  }d+d,|iz  } |j                  |        |st        j                  d$fd-f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                        t        j                        t        j                  |      d.z  }!d/d0|!iz  }"|j                  |"       t        j                  |d      i z  }#d1d2|#iz  }$t        t        j                  |$            dx}x}x}x}x}x}x}x}x}x}x}x}}y)3uR   차단 7: guard.sh FAIL 상태 → merge exit 1 (HUMAN_APPROVED 미달과 동시).ztask-2449-block-7rT   r   r7   r   r   r1   r   r   r   Nr   r   r`   r   r   rt   rW   r   r   r   r   r   rv   rZ   r   r|   r9   r:   r;   rS   r@   rk   u   차단blockedr^   )z.%(py3)s in %(py7)s
{%(py7)s = %(py5)s.stderr
})rr   r>   r@   z%(py9)srs   )z2%(py12)s in %(py16)s
{%(py16)s = %(py14)s.stderr
})r   r   rv   z%(py18)srw   )zh%(py21)s in %(py29)s
{%(py29)s = %(py27)s
{%(py27)s = %(py25)s
{%(py25)s = %(py23)s.stderr
}.lower
}()
})py21py23py25py27r}   z%(py31)spy31zassert %(py34)spy34)r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   rI   r   r   r   )%r,   r1   rL   rM   r   r   r   r   r   r`   rN   r   r   r   r   r   r   r   r   r   r:   rO   rP   r   r   @py_assert11r   @py_assert20@py_assert24@py_assert26@py_assert28@py_assert22@py_format19r   @py_format32@py_format33@py_format35s%                                        r   'test_blocked_guard_sh_fail_blocks_merger    s   !G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888) :C)9)4499499994999999|999|999999C999C999999999999)99949999999999:!HFHCH<	7FC8H8CCHqHCqHHHHCqHHHHHH<HHH<HHH	HHHHHH7HHH7HHHFHHHCHHH8HHHCHHHqHHHHHHHH+6D??a?a?a44?aiit{{i{*ihi$++ih+.EiiVZVaVaiVaVgVgiVgViiViIiiiii{iiiiiiiiitiiitiii{iiiiiiih+iiihiiiiii$iii$iii+iiiiiiiViiiiiiiiiiVZiiiVZiiiVaiiiVgiiiViiiiiiiiiiiiiiiiir   c           	        ~ d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}t        d|d      }	|	j                  }d}||k(  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |	      rt        j                  |	      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}
}d}|	j                  }||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  |	      rt        j                  |	      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u1   차단 8: HUMAN_APPROVED 미달 → merge exit 1.ztask-2449-block-8rT   r   r7   r   r   r1   r   r   r   NrZ   r   r|   r9   r:   r;   rS   r@   rk   r^   r   r   )r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   rI   )r,   r1   rL   rM   r   r   r   r   r   r:   rN   rO   rP   r   r   s                  r   0test_blocked_human_approval_missing_blocks_merger     s   !G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888+6D??a?a?a44?a*t{{*{****{*********t***t***{*******r   c                   d}d}t        ||      }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}x}}dD ]x  }	t        |	|      }
|
j                  }d}||k(  }|sKt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               nddt	        j
                         v st        j                  |	      rt        j                  |	      nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |
      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}
x}x}}{ d}d}d}t        ||||      }|j                  }d}||k(  }|sFt        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}x}x}x}}t        d|dddi      }|j                  }d}||k(  }
|
st        j                  d|
fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      d z  }t        j                  d!|j                         d"z   d#|iz  }t        t        j                  |            dx}x}
}d$}|j                  }||v }|st        j                  d%|fd&||f      t        j                  |      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      d'z  }d(d#|iz  }t        t        j                  |            dx}x}}t        j                  t        | |      j                               }|d)   d*   }d+}
||
u }|slt        j                  d,|fd-||
f      t        j                  |      t        j                  |
      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}
|d)   d1   }d}
||
u}|slt        j                  d2|fd3||
f      t        j                  |      t        j                  |
      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}
|d)   d4   }d}
||
u}|slt        j                  d2|fd3||
f      t        j                  |      t        j                  |
      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}
|d5   }d6}
||
k(  }|slt        j                  d|fd7||
f      t        j                  |      t        j                  |
      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}
|d8   d9   }d}
||
u}|slt        j                  d2|fd3||
f      t        j                  |      t        j                  |
      d.z  }d/d0|iz  }t        t        j                  |            dx}x}}
y):uR   bypass 9: TASKCTL_BYPASS=1 set 시 evidence에 bypass=true 기록 + stderr 경고.ztask-2449-bypassrT   r   r7   r   r   r1   r   r   r   Nr   r   r`   r   r   rt   rW   r   777r   r   r   rv   rZ   r   TASKCTL_BYPASSr   )r   r9   r:   r;   u   bypass dry-run 머지 실패: r?   r@   zBYPASS USEDr^   r   r   rS   bypassusedT)is)z%(py1)s is %(py4)sr   r   r   ts)is not)z%(py1)s is not %(py4)sactorrl   DONEr   r   merge_timestamp)r   rA   rB   rC   rD   rE   rF   rG   rJ   rK   rH   rI   r   r   r2   r   )r,   r1   rL   rM   r   r   r   r   r   r`   rN   r   r   r   r   r   r   r   r   r   r:   rO   rP   r   r   r    re   r   s                               r   )test_bypass_records_evidence_and_proceedsr&  /  sM    G8<(8(338q83q88883q888888<888<888888888888888(8883888q8888888) :C)9)4499499994999999|999|999999C999C999999999999)99949999999999:!JFJEJ<	7FE:J:EEJJEJJJJEJJJJJJ<JJJ<JJJ	JJJJJJ7JJJ7JJJFJJJEJJJ:JJJEJJJJJJJJJJJ+-s35D??OaO?aOOO?aOOOOOO4OOO4OOO?OOOaOOO#A$++!OOOOOOOO'DKK'=K''''=K'''=''''''D'''D'''K'''''''JJ{>7;EEGHE?6"*d*"d****"d***"***d*******?4 ,, ,,,, ,,, ,,,,,,,,,,?7#/4/#4////#4///#///4///////!+V+!V++++!V+++!+++V+++++++./;t;/t;;;;/t;;;/;;;t;;;;;;;r   c                   t         dz  dz  dz  }|j                  } |       }|sddt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }t        t	        j                  |            dx}}| dz  }t        |d	
       d}t        j                  dt        |      gt        |      |ddd      }|j                  }d}||k(  }|st	        j                  d|fd||f      dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}}d}|j                  }||v }|st	        j                  d|fd||f      t	        j                  |      dt        j                         v st	        j
                  |      rt	        j                  |      ndt	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            dx}x}}y)uS   다른 브랜치에서 origin/main 으로 push 시도 → refspec 검사로 차단.r   r   r   rh   r   rj   Nr   z	feature/xr   z4refs/heads/feature/x abc123 refs/heads/main 0000000
r   Tr   r   r|   r7   r9   r:   r;   rS   r@   r   r^   r   r   )r   r~   rD   rE   rB   rF   rG   rJ   rK   r   r   r   r   rA   rC   rI   )r*   r   rL   rN   re   r   refspec_inputr:   rM   rO   rP   r   r   s                r   !test_pre_push_refspec_blocks_mainr)  H  s   y ;.;D;;;==44;=;&IIk2KM>>	T	N$	D ??a?a?a44?a(7DKK7(K7777(K777(777777D777D777K7777777r   )r   r   r   zdict | Noner   zPath | Nonereturnzsubprocess.CompletedProcess)r0   r   r1   r   r*  r   )r   )r   r   r   r   r*  None)$__doc__
__future__r   builtinsrD   _pytest.assertion.rewrite	assertionrewriterB   r   r   r   r   pathlibr   pytestr   r   r   fixturer,   r2   rQ   rf   r   r   r   r   r   r   r   r  r  r  r&  r)  r/   r   r   <module>r5     s   & #    	  
  &'	
i
,
. 15$(	!	-H	 	 	>C>R&"4'& .1C"8&.bj+<28r   