
    jI/                    0   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mZ  ee      j                         j                   d   Zedz  dz  ZdZd	Zd
ZddZddZddZ G d d      Z G d d      Z G d d      Z G d d      Z G d d      Zy)u
  
task-2576 TODO-4 신규 회귀: stash_audit.py existence guard 정합화 (-x → -f, 3 위치).

배경:
- python3 invoke이므로 execute bit (-x) 의미 없음. `-f` (file 존재) 가드가 정합.
- PR #125 (attempt-3) 에서 line 1166만 -f 로 수정. line 42, 1145 는 -x 잔존.
- task-2576 TODO-4: 3 위치 모두 -f 로 통일.

검증:
1. -x stash_audit.py 패턴 0건
2. -f stash_audit.py 패턴 정확히 3건 (line 42, 1145, 1166)
3. (선택) 동적: 실행 권한 없는 stash_audit.py 도 -f 분기 통과
    )annotationsN)Path   scriptszfinish-task.sh      i  c                 .    t         j                  d      S Nutf-8encoding)FINISH_TASK_SH	read_text     T/home/jay/workspace/tests/regression/test_finish_task_stash_audit_existence_guard.py_read_shr   $   s    ##W#55r   c                 J    t         j                  d      j                         S r
   )r   r   
splitlinesr   r   r   _read_sh_linesr   (   s    ##W#5@@BBr   c                    t        j                  |       }t        |      D cg c]  \  }}|j                  |      s|dz    c}}S c c}}w )uF   주어진 패턴과 일치하는 라인 번호(1-based) 목록 반환.   )recompile	enumeratesearch)patterncontent_linescompiledilines        r   _find_pattern_linesr"   ,   s<    zz'"H!*=!9SgaX__T=RAESSSs
   A	A	c                      e Zd ZdZd Zd Zy)TestNoMinusXGuarduC   TODO-4 회귀 — -x stash_audit.py 패턴이 0건이어야 한다.c                   t               }t        j                  d|      }t        |      }d}||k(  }|st	        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t	        j                  |      t	        j                  |      dz  }t	        j                  dt        |       d	| d
      dz   d|iz  }t        t	        j                  |            dx}x}}y)u   
        finish-task.sh 전체에서 '[ -x ... stash_audit.py' 패턴이 0건이어야 한다.
        python3 로 invoke 하는 스크립트이므로 execute bit 의미 없음.
        z\[\s+-x\s+.*stash_audit\.pyr   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenmatchespy0py1py3py6u/   TODO-4 회귀 감지: -x stash_audit.py 패턴 u   건 발견.
발견 내용: uQ   
fix: -x → -f 로 교체 필수 (python3 invoke이므로 execute bit 불필요)
>assert %(py8)spy8Nr   r   findallr)   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgAssertionError_format_explanationselfcontentr*   @py_assert2@py_assert5@py_assert4@py_format7@py_format9s           r   test_minus_x_stash_audit_absentz1TestNoMinusXGuard.test_minus_x_stash_audit_absent9   sA   
 ***;WE7| 	
q 	
|q  	
 	
 		
|q 	
 	
 
6		
 	
 	  	
 	
 
		  	
 	
 
6		
 	
 	  	
 	
 
		  	
 	
 
		  	
 	
 
		  ! 	
 	
  >c'l^ L%Y '__	
 	
 	
 		
 	
 	
r   c                   t               }t        j                  d|      }t        |      }d}||k(  }|st	        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t	        j                  |      t	        j                  |      dz  }t	        j                  dt        |       d	|       d
z   d|iz  }t        t	        j                  |            dx}x}}y)ug   
        'if [ -x' 형태로 stash_audit.py 가드를 체크하는 패턴이 없어야 한다.
        z(if\s+\[\s+-x\s+["\']?\$.*stash_audit\.pyr   r&   r(   r)   r*   r+   u/   TODO-4 회귀: if [ -x ] stash_audit.py 패턴    건 발견: r0   r1   Nr2   r=   s           r   &test_minus_x_guard_not_in_any_if_blockz8TestNoMinusXGuard.test_minus_x_guard_not_in_any_if_blockF   s)    ***H'R7| 	
q 	
|q  	
 	
 	
|q 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  ! 	
 	
  >c'l^<X_W`a	
 	
 	
 	
 	
 	
r   N)__name__
__module____qualname____doc__rE   rH   r   r   r   r$   r$   6   s    M
	
r   r$   c                      e Zd ZdZd Zd Zy)TestExactlyThreeMinusFGuardsuQ   TODO-4 fix 박제 — -f stash_audit.py 가드가 정확히 3건이어야 한다.c           	     2   t               }t        j                  d|      }t        |      }|t        k(  }|s\t        j                  d|fd|t        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t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  dt        |       d	t         d
| d      dz   d|iz  }t        t        j                  |            dx}}y)u   
        finish-task.sh 에서 '[ -f ... stash_audit.py' 패턴이 정확히 3건이어야 한다.
        (line 42, 1145, 1166 인근 3개 위치)
        $\[\s+-f\s+["\']?\$?.*stash_audit\.pyr&   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py5)sr)   r*   EXPECTED_F_GUARD_COUNTr,   r-   r.   py5u/   TODO-4 fix 위반: -f stash_audit.py 패턴이    건 (기대: u   건).
발견 내용: u*   
예상 위치: line 42, 1145, 1166 인근
>assert %(py7)spy7Nr   r   r3   r)   rR   r4   r5   r6   r7   r8   r9   r:   r;   r<   )r>   r?   r*   r@   rB   @py_format6@py_format8s          r   'test_minus_f_stash_audit_count_is_threezDTestExactlyThreeMinusFGuards.test_minus_f_stash_audit_count_is_threeY   sa   
 ***DgN7| 	
|55 	
 	
 		
|5 	
 	
 
6		
 	
 	  	
 	
 
		  	
 	
 
6		
 	
 	  	
 	
 
		  	
 	
 
		  	
 	
 
6		
 	
 	  6 	
 	
 
		  6 	
 	
  >c'l^=YoXp q%Y '89	
 	
 	
 		
 	
r   c                4   t               }d}t        j                  ||      }t        |      }|t        k(  }|s[t        j                  d|fd|t        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t        j                  |      dt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  dt        |       d	t         d
|       dz   d|iz  }t        t        j                  |            dx}}y)u   
        '[ -f "$WORKSPACE/scripts/stash_audit.py" ]' 문자열이 정확히 3번 나타나야 한다.
        (TODO-4 fix 정확한 문자열 박제)
        z5if\s+\[\s+-f\s+"?\$\w+/scripts/stash_audit\.py"?\s*\]r&   rQ   r)   r*   rR   rS   u:   TODO-4 fix 위반: if [ -f .../stash_audit.py ] 패턴이 rU   u   건).
발견: rV   rW   NrX   )r>   r?   r   r*   r@   rB   rY   rZ   s           r   +test_specific_f_guard_string_appears_thricezHTestExactlyThreeMinusFGuards.test_specific_f_guard_string_appears_thricef   sb   
 *J**Wg.7| 	
|55 	
 	
 	
|5 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
6	
 	
   6 	
 	
 
	  6 	
 	
  IWVcdzc{ |i!	
 	
 	
 	
 	
r   N)rI   rJ   rK   rL   r[   r]   r   r   r   rN   rN   V   s    [

r   rN   c                      e Zd ZdZd Zd Zy)TestFGuardLineNumbersu_   TODO-4 fix 박제 — -f 가드 3건의 라인 번호가 예상 범위 내에 있어야 한다.c           
        t               }t        d|      }t        |      }|t        k(  }|s[t	        j
                  d|fd|t        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t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }t	        j                  dt        |       d	t         d
|       dz   d|iz  }t        t	        j                  |            dx}}|D ]g  }t        |k  }|t        k  }|r|sIt	        j
                  d||fdt        |t        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                  t              rt	        j                  t              nddz  }	t	        j                  d| dt         dt         d      dz   d|	iz  }
t        t	        j                  |
            dx}}j y)u   
        -f stash_audit.py 가드의 라인 번호가 모두 LINE_RANGE_MIN < line < LINE_RANGE_MAX
        범위 내에 있어야 한다.
        rP   r&   rQ   r)   guard_linesrR   rS   u(   TODO-4: -f 가드 라인 수 불일치 (u   건, 기대 u   건). 라인: rV   rW   N)<rb   )z%(py0)s < %(py3)sz%(py3)s < %(py4)sLINE_RANGE_MINlinenoLINE_RANGE_MAX)r,   r.   py4u   TODO-4: -f 가드 라인 u    이 예상 범위(~u2   ) 밖.
finish-task.sh 구조 변경 확인 필요.z
>assert %(py6)sr/   )r   r"   r)   rR   r4   r5   r6   r7   r8   r9   r:   r;   r<   rc   re   )r>   linesra   r@   rB   rY   rZ   rd   @py_assert1@py_format5rC   s              r   $test_f_guard_lines_in_expected_rangez:TestFGuardLineNumbers.test_f_guard_lines_in_expected_range|   s   
  )3
 ; 	
#99 	
 	
 	
#9 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	   	
 	
 
6	
 	
  $: 	
 	
 
	 $: 	
 	
  7s;7G6HUkTl m"m%	
 	
 	
 	
 	
 " 	F!F; F^;   >F^   v   "   I "   v   %+   I %+   v   .<   I .<    ,F83F~FVVWXfWg h> >    	r   c                   t               }t        d|      }t        |      }|t        k(  }|s/t	        j
                  d|fd|t        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t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              nddz  }dd	|iz  }t        t	        j                  |            d
x}}|D cg c]
  }|dk  s	| }}|D cg c]
  }|dkD  s	| }	}t        |      }d}
||
k\  }|st	        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t	        j                  |      t	        j                  |
      dz  }t	        j                  d|       dz   d|iz  }t        t	        j                  |            d
x}x}}
t        |	      }d}
||
k\  }|st	        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t	        j                  |      t	        j                  |
      dz  }t	        j                  d|       dz   d|iz  }t        t	        j                  |            d
x}x}}
y
c c}w c c}w )u   
        -f 가드 3건이 스크립트 앞부분(< 100) 과 뒷부분(> 1000) 에 분포해야 한다.
        (line 42 는 early, line 1145/1166 은 late — 분산 검증)
        rP   r&   rQ   r)   ra   rR   rS   zassert %(py7)srW   N   i  r   >=z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)searlyr+   u>   TODO-4: line 42 인근 early -f 가드 없음. 발견 라인: r0   r1   r   lateuI   TODO-4: line 1145/1166 인근 late -f 가드 2건 미만. 발견 라인: )r   r"   r)   rR   r4   r5   r6   r7   r8   r9   r;   r<   r:   )r>   rh   ra   r@   rB   rY   rZ   lrq   rr   rA   rC   rD   s                r   1test_f_guard_lines_cover_early_and_late_positionszGTestFGuardLineNumbers.test_f_guard_lines_cover_early_and_late_positions   s   
  )3
 ;9#99999#9999999s999s999999;999;999999999#9999#99999999'3q1s733&3a!d(335z 	
Q 	
zQ 	
 	
 	
zQ 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  	
 	
  M[MZ	
 	
 	
 	
 	
 4y 	
A 	
yA~ 	
 	
 	
yA 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		  	
 	
  XXcWde	
 	
 	
 	
 	
 	
 43s   %
O 0O :
O%O%N)rI   rJ   rK   rL   rk   rt   r   r   r   r_   r_   y   s    i(
r   r_   c                  "    e Zd ZdZd Zd Zd Zy)TestExecuteBitDependencyRemoveduT   TODO-4 doctrine 박제 — python3 invoke이므로 execute bit 의존 제거 확인.c                   t               }d}t        j                  ||      }t        |      }d}||k(  }|st	        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t	        j                  |      t	        j                  |      dz  }t	        j                  dt        |       d	| d
      dz   d|iz  }t        t	        j                  |            dx}x}}y)u   
        finish-task.sh 내에서 stash_audit.py 에 chmod +x 를 부여하거나
        execute bit 를 요구하는 패턴이 없어야 한다.
        zchmod\s+\+x.*stash_audit\.pyr   r&   r(   r)   r*   r+   u5   TODO-4 의존 잔존: chmod +x stash_audit.py 패턴 rG   u4   
python3 로 invoke 하므로 execute bit 불필요.r0   r1   Nr2   	r>   r?   r   r*   r@   rA   rB   rC   rD   s	            r   &test_no_chmod_x_stash_audit_dependencyzFTestExecuteBitDependencyRemoved.test_no_chmod_x_stash_audit_dependency   sE   
 *1**Wg.7| 	
q 	
|q  	
 	
 	
|q 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
	  ! 	
 	
  DCL>Q]^e]f gB B	
 	
 	
 	
 	
 	
r   c                   t               }d}t        j                  ||      }t        |      }d}||k\  }|st	        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t	        j                  |      t	        j                  |      dz  }t	        j                  d      d	z   d
|iz  }t        t	        j                  |            dx}x}}y)u   
        finish-task.sh 내에서 'python3 ... stash_audit.py' 형태의 invoke 가
        존재해야 한다 (execute bit 없이 직접 호출 방식 확인).
        z'python3\s+["\']?\$?\w+.*stash_audit\.pyr   rn   rp   r)   r*   r+   ui   TODO-4: python3 stash_audit.py invoke 패턴 없음.
stash_audit.py 는 python3 로 invoke 되어야 함.r0   r1   Nr2   rx   s	            r   #test_python3_invoke_pattern_presentzCTestExecuteBitDependencyRemoved.test_python3_invoke_pattern_present   s'   
 *<**Wg.7| 	
q 	
|q  	
 	
 	
|q 	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
6	
 	
   	
 	
 
	  	
 	
 
	  	
 	
 
	  ! 	
 	
 C	
 	
 	
 	
 	
 	
r   c                6   t               }|j                         }g }t        |d      D ]D  \  }}|j                         }d|v s|j	                  d      s-d|v s2|j                  ||f       F t        |      }d}||k(  }	|	st        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t        j                  |      t        j                  |      d	z  }
t        j                  d
|       dz   d|
iz  }t        t        j                  |            dx}x}	}y)u   
        './stash_audit.py' 또는 '$WORKSPACE/scripts/stash_audit.py' 를 python3 없이
        직접 실행하는 패턴이 없어야 한다.
        r   stash_audit.py$r   r&   r(   r)   
violationsr+   u;   TODO-4 경고: stash_audit.py 직접 실행 패턴 발견: r0   r1   N)r   r   r   strip
startswithappendr)   r4   r5   r6   r7   r8   r9   r:   r;   r<   )r>   r?   rh   r   r    r!   strippedr@   rA   rB   rC   rD   s               r   3test_stash_audit_not_invoked_directly_as_executablezSTestExecuteBitDependencyRemoved.test_stash_audit_not_invoked_directly_as_executable   sw   
 *""$
 * 	5GAtzz|H8+&&s+0@H0L%%q(m4	5 : 	
! 	
!# 	
 	
 	
! 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		 #$ 	
 	
  J*V	
 	
 	
 	
 	
 	
r   N)rI   rJ   rK   rL   ry   r{   r   r   r   r   rv   rv      s    ^


r   rv   c                  "    e Zd ZdZd Zd Zd Zy)!TestMinusFPassesWithoutExecuteBitup   
    TODO-4 동적 회귀: 실행 권한 없는 stash_audit.py 를 -f 로 체크하면 통과해야 한다.
    c                   |dz  }|j                  dd       |j                  t        j                  t        j                  z  t        j
                  z  t        j                  z         t        j                  ddd| dgd	d	
      }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  }t        j                   d|j                        dz   d|iz  }t#        t        j$                  |            dx}x}}y)u   
        임시 디렉토리에 chmod 644 (실행 권한 없음) 의 stash_audit.py 생성 후
        bash -c '[ -f path ]' 가 성공(exit 0) 해야 한다.
        r}   # fake stash_audit.py
r   r   bash-cz[ -f "!" ] && echo "PASS" || echo "FAIL"Tcapture_outputtextPASSinz.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
}result_fr-   r.   rT   uE   -f 체크가 실행 권한 없는 파일에 대해 실패함. stdout=rV   rW   N
write_textchmodstatS_IRUSRS_IWUSRS_IRGRPS_IROTH
subprocessrunstdoutr4   r5   r9   r6   r7   r8   r:   r;   r<   )	r>   tmp_pathfake_scriptr   @py_assert0rB   r@   rY   rZ   s	            r   .test_f_check_passes_without_execute_permissionzPTestMinusFPassesWithoutExecuteBit.test_f_check_passes_without_execute_permission   sK   
 !1187K$,,5Dt||ST >>TVK=0QRS

  	
 	
v( 	
 	
v 	
 	
 		  	
 	
	6	
 	
  " 	
 	
 		 " 	
 	
 		 ) 	
 	
  TT\TcTcSfg	
 	
 	
 	
 	
 	
r   c                   |dz  }|j                  dd       |j                  t        j                  t        j                  z  t        j
                  z  t        j                  z         t        j                  ddd| dgd	d	
      }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  }t        j                   d|j                        dz   d|iz  }t#        t        j$                  |            dx}x}}y)u   
        대조군: -x 체크는 실행 권한 없는 파일에 대해 실패해야 한다.
        (따라서 -x 는 python3 invoke 스크립트 가드에 부적합함을 실증)
        r}   r   r   r   r   r   z[ -x "r   Tr   FAILr   r   result_xr   uZ   -x 체크가 실행 권한 없는 파일에 대해 통과함 — 예상과 다름. stdout=rV   rW   Nr   )	r>   r   r   r   r   rB   r@   rY   rZ   s	            r   -test_x_check_fails_without_execute_permissionzOTestMinusFPassesWithoutExecuteBit.test_x_check_fails_without_execute_permission   sK   
 !1187K$,,5Dt||ST >>TVK=0QRS

  	
 	
v( 	
 	
v 	
 	
 		  	
 	
	6	
 	
  " 	
 	
 		 " 	
 	
 		 ) 	
 	
  iiqixixh{|	
 	
 	
 	
 	
 	
r   c                   t               }t        t        j                  d|            }t        t        j                  d|            }|t        k(  }|st        j                  d|fd|t        f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  t              rt        j                  t              nddz  }t        j                  d| d	t         d
      dz   d|iz  }t        t        j                  |            d}d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      dz   d|iz  }	t        t        j                  |	            dx}}y)u   
        finish-task.sh 이 실제로 -f 를 사용하므로, 실행 권한 없는 stash_audit.py 도
        분기를 탈 수 있음을 정적 + 동적 조합으로 최종 박제.
        rP   z$\[\s+-x\s+["\']?\$?.*stash_audit\.pyr&   )z%(py0)s == %(py2)sf_countrR   )r,   py2u   TODO-4: -f 가드 u   건 (기대 u   건)z
>assert %(py4)srf   Nr   )z%(py0)s == %(py3)sx_count)r,   r.   u   TODO-4: -x 가드 u   건 (기대 0건)z
>assert %(py5)srT   )r   r)   r   r3   rR   r4   r5   r6   r7   r8   r9   r:   r;   r<   )
r>   r?   r   r   ri   @py_format3rj   r@   @py_format4rY   s
             r   3test_finish_task_uses_f_not_x_for_stash_audit_guardzUTestMinusFPassesWithoutExecuteBit.test_finish_task_uses_f_not_x_for_stash_audit_guard  s   
 *bjj!H'RSbjj!H'RS00 	
 	
w0 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  1 	
 	
 		 1 	
 	
  !	6L5MTR	
 	
 	
 	
 	
  	
w!| 	
 	
w! 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
  !	):;	
 	
 	
 	
 	
r   N)rI   rJ   rK   rL   r   r   r   r   r   r   r   r      s    
(
(
r   r   )returnstr)r   	list[str])r   r   r   r   r   z	list[int])rL   
__future__r   builtinsr6   _pytest.assertion.rewrite	assertionrewriter4   r   r   r   pathlibr   __file__resolveparents	WORKSPACEr   rR   rc   re   r   r   r"   r$   rN   r_   rv   r   r   r   r   <module>r      s    #   	   N""$,,Q/	Y&)99   6CT
 
@
 
F+
 +
d/
 /
l<
 <
r   