
    jV,                         d 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ed	dfd
Zded	dfdZddZddZddZy)u  
test_stash_lifecycle_fail_stop_bash.py
task: task-2571+2
작성자: 카르티케야 (개발4팀 백엔드)

해소 대상 findings:
- Gemini HIGH: stash-lifecycle dispatch heredoc python failure가 bash에서
  fatal로 전파되지 않아 다음 stash 처리가 계속될 수 있음.
  → Fix B (라인 1175): `|| echo "[WARN]..."` → `|| { echo "[ERROR]..." >&2; exit 1; }`
- Gemini MEDIUM: stash_audit.py가 execute bit 없어도 `-x` 가드에 막혀 실행 경로를
  통과하지 못함.
  → Fix A (라인 1166): `if [ -x ... ]` → `if [ -f ... ]`

검증 목표:
1. bash 계층에서 python heredoc sys.exit(1) 이 non-zero exit code로 전파되는가
   (기존 test_stash_lifecycle_failstop.py 는 python 본문 직접 실행 → bash 계층 갭)
2. stash_audit.py execute bit 없어도 -f 가드 기준 실행 경로가 유지되는가
   (-x 가드는 통과 못 함 → -f 가드만 통과 → fix 효용 입증)
    N)Path   scriptszfinish-task.shz#task-2571: stash lifecycle dispatchtmp_pathreturnc                 
   t        j                  d      }| dz  }|j                  t        j                  d| d      d       |j                  |j	                         j
                  t        j                  z         t        j                  dt        |      g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  }t        j"                  d|j$                  d|j&                        dz   d|iz  }t)        t        j*                  |            dx}x}}g }d}	|j&                  }
|
j,                  } |       }|	|v }|}|s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                   |
      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                   |      dz  }dd|iz  }|j/                  |       t        j0                  |d      i z  }t        j"                  d |j&                        d!z   d"|iz  }t)        t        j*                  |            dx}x}x}	x}x}
x}x}x}x}}| d#z  }|j                  t        j                  d$| d      d       |j                  |j	                         j
                  t        j                  z         t        j                  dt        |      g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)|j$                        dz   d|iz  }t)        t        j*                  |            dx}x}}y)*u  
    Gemini HIGH 해소: bash heredoc 내 python이 sys.exit(1) 할 때,
    Fix B (|| { echo "[ERROR]..." >&2; exit 1; }) 덕분에 bash exit code가 non-zero가 되어야 한다.

    검증 방식:
    - fix 전 패턴: `<<'PYEOF' || echo "[WARN]..."` → bash exit code = 0 (non-fatal)
    - fix 후 패턴: `<<'PYEOF' || { echo "[ERROR]..." >&2; exit 1; }` → bash exit code != 0

    임시 bash 스크립트에 두 패턴을 각각 삽입하여 실제 실행 결과를 비교한다.
    z+        import sys
        sys.exit(1)
    ztest_fixed.shz            #!/usr/bin/env bash
            python3 - <<'PYEOF' || { echo "[ERROR] stash-lifecycle dispatch failed (fatal)" >&2; exit 1; }
z
PYEOF
        utf-8encodingbashTcapture_outputtextr   !=)z2%(py2)s
{%(py2)s = %(py0)s.returncode
} != %(py5)sresult_fixedpy0py2py5uY   Fix B (fatal exit 전파) 실패: python sys.exit(1) 후 bash exit code가 0임.
stdout: 	
stderr: 
>assert %(py7)spy7NfatalERRORin)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)z2%(py16)s in %(py20)s
{%(py20)s = %(py18)s.stderr
})py16py18py20z%(py22)spy22   u<   Fix B: [ERROR] fatal 메시지가 stderr에 없음.
stderr: z
>assert %(py25)spy25ztest_warn.shz}            #!/usr/bin/env bash
            python3 - <<'PYEOF' || echo "[WARN] stash-lifecycle dispatch failed (non-fatal)"
==z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sresult_warnuH   대조 검증 이상: WARN only 패턴이 exit 0이 아님.
returncode: z	
stdout: )textwrapdedent
write_textchmodstatst_modeS_IEXEC
subprocessrunstr
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstdoutstderrAssertionError_format_explanationlowerappend_format_boolop)r   mock_python_bodyfixed_scriptr   @py_assert1@py_assert4@py_assert3@py_format6@py_format8@py_assert2@py_assert6@py_assert8@py_assert10@py_assert0@py_assert15@py_assert19@py_assert17@py_format12@py_format14@py_format21@py_format23@py_format24@py_format26warn_scriptr+   s                            K/home/jay/workspace/tests/regression/test_stash_lifecycle_fail_stop_bash.py8test_bash_heredoc_python_failure_propagates_nonzero_exitr\   &   s      ( 	 o-L    	 	    |((*22T\\AB>>	\"#L
 "" a "a'  	"a   	  	    	    	 #   	 '(   	&&) *&&)	+   	 
7 l)) )// /1 711 W @S@S W@S5S   71          #    #    *    0    2     W@S    6=      AM    AM    AT       	&&)	+       ^+K    	 	    k&&(004<<?@..	[!"K !! Q !Q&  	!Q   	  	    	    	 "   	 &'   	"--. /%%(	*   	      c                 "   | dz  }|j                  dd       |dz  }|j                  dd       |j                  d       |j                         j                  }t        j
                  }||z  }| }|st        j                  d	      d
z   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t        j                  |      dz  }t        t        j                  |            dx}x}}t        |       }| dz  }	|	j                  t        j                   d| d      d       |	j                  |	j                         j                  t        j"                  z         t%        j&                  dt        |	      g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|
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  }t        j                  d!|
j.                        dz   d|iz  }t        t        j                  |            dx}x}}| d"z  }|j                  t        j                   d| d#      d       |j                  |j                         j                  t        j"                  z         t%        j&                  dt        |      g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|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  }t        j                  d'|j.                        dz   d|iz  }t        t        j                  |            dx}x}}g }d}|
j.                  }||v }|}|r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  }|j1                  |       |rt        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  }|j1                  |       t        j2                  |d      i z  }t        j                  d0      d1z   d2|iz  }t        t        j                  |            dx}x}x}x}x}x}x}}y)3u  
    Gemini MEDIUM 해소: stash_audit.py가 execute bit 없이 chmod 644로 존재할 때,
    Fix A (-f 가드)는 통과하고 구 패턴 (-x 가드)는 통과하지 못함을 검증한다.

    검증 방식:
    - tmp_path/scripts/stash_audit.py 생성 (chmod 644, execute bit 없음)
    - `-f` 조건 bash 가드 스크립트 실행 → then 블록 진입 확인
    - `-x` 조건 bash 가드 스크립트 실행 → then 블록 미진입 확인
    r   T)parentsexist_okstash_audit.pyz# dummy stash_audit.py
r	   r
   i  uO   전제 실패: execute bit 제거 안 됨 (chmod 644 이후에도 IXUSR 존재)z=
>assert not (%(py0)s & %(py3)s
{%(py3)s = %(py1)s.S_IXUSR
})moder0   )r   py1r   Nz
guard_f.shz7            #!/usr/bin/env bash
            WORKSPACE="z"
            if [ -f "$WORKSPACE/scripts/stash_audit.py" ]; then
                echo "ENTERED_THEN"
            else
                echo "SKIPPED_ELSE"
            fi
        r   r   r   r(   r*   result_fr   u1   -f 가드 스크립트 실행 실패: returncode=r   r   r   ENTERED_THENr   )z.%(py1)s in %(py5)s
{%(py5)s = %(py3)s.stdout
})rc   r   r   u^   Fix A (-f 가드): execute bit 없는 stash_audit.py에 대해 then 블록 미진입.
stdout: z
guard_x.shz"
            if [ -x "$WORKSPACE/scripts/stash_audit.py" ]; then
                echo "ENTERED_THEN"
            else
                echo "SKIPPED_ELSE"
            fi
        result_xu1   -x 가드 스크립트 실행 실패: returncode=SKIPPED_ELSEuc   대조 검증 이상: -x 가드가 execute bit 없는 파일에 대해 then 블록 진입.
stdout: )z.%(py3)s in %(py7)s
{%(py7)s = %(py5)s.stdout
})r   r   r   z%(py9)sr   )z2%(py12)s in %(py16)s
{%(py16)s = %(py14)s.stdout
})py12py14r"   z%(py18)sr#   uN   Fix A 효용 미입증: -f 통과 XOR -x 차단 패턴이 성립하지 않음.z
>assert %(py21)spy21)mkdirr.   r/   r0   r1   S_IXUSRr7   r=   r9   r:   r;   r<   r@   rA   r5   r,   r-   r2   r3   r4   r6   r8   r?   r>   rC   rD   )r   scripts_dirdummy_pyrb   rL   rH   @py_assert5rJ   	workspacef_guard_scriptrd   rG   rI   rK   rP   x_guard_scriptrf   rM   @py_assert11rQ   @py_assert13@py_format10@py_format17@py_format19@py_format20@py_format22s                             r[   8test_file_guard_passes_without_execute_bit_x_guard_failsrz   q   s/    Y&KdT2--H2WENN5 ==?""D|| |# #$ $   	Z                       $      HI ,N !{ #	 	    ,,.66EF~~	^$%H
  ! !#  !                  #$    <H<O<O;P Q??%	'      X__ >_,  >_          &    &    -   	??%	'     ,N !{ #	 	    ,,.66EF~~	^$%H
  ! !#  !                  #$    <H<O<O;P Q??%	'    
  X__ >_,  >_          &    &    -   	??%	'    > X__ >_,  8?? ?1R   >_          &    &    -     ?    2@      DL    DL    DS        	Y      r]   c            	      @   t         j                  d      } | j                         }d}t        |      D ]  \  }}t        |v s|} n d}||u}|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t              d	z   d
|iz  }t        t        j                  |            dx}}d}	t        |t        |dz   t!        |                  D ]3  }d||   v s||   j#                         j%                  d      s.||   }	 n d}|	|u}|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}}d}
|
|	v }|st        j                  d|fd|
|	f      t        j                  |
      dt        j                         v st        j                  |	      rt        j                  |	      nddz  }t        j                  d|	      d	z   d
|iz  }t        t        j                  |            dx}
}d}
|
|	v}|st        j                  d|fd|
|	f      t        j                  |
      dt        j                         v st        j                  |	      rt        j                  |	      nddz  }t        j                  d|	      d	z   d
|iz  }t        t        j                  |            dx}
}y)u   
    Fix A 정적 검증: finish-task.sh 라인 1166 영역(lifecycle dispatch 컨텍스트)에
    `-f` 가드가 존재하고, 해당 컨텍스트에 `-x` 가드가 없어야 한다.
    r	   r
   N)is not)z%(py0)s is not %(py3)s
marker_idxr   r      마커 미발견: 
>assert %(py5)sr   
   ra   zif [
guard_lineu   lifecycle dispatch 마커(u5   ) 이후 10라인 내 stash_audit.py 가드 미발견z[ -f r   z%(py1)s in %(py3)src   r   uN   Fix A 실패: lifecycle dispatch 가드에 `-f` 없음.
실제 가드 라인: z[ -x not inz%(py1)s not in %(py3)suX   Fix A 실패: lifecycle dispatch 가드에 여전히 `-x` 존재.
실제 가드 라인: )FINISH_TASK_SH	read_text
splitlines	enumerateLIFECYCLE_DISPATCH_MARKERr7   r8   r9   r:   r;   r<   r=   r@   rA   rangeminlenstrip
startswith)r   linesr}   ilinerL   rG   @py_format4rJ   r   rP   s              r[   'test_static_fix_a_line1166_uses_f_guardr      s   
 ##W#5DOOE "JU# 4$,J "U:T!UUU:TUUUUUU:UUU:UUUTUUU%78Q7T#UUUUUUU!J:s:?CJ?@ uQx'E!HNN,<,G,G,OqJ " :T!  :T              "    %ZL0ef      7j   7j          !    !   !!+	0      7*$  7*          %    %   !!+	0    r]   c                     t         j                  d      } | j                  t              }d}| }||k7  }|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t              d	z   d
|iz  }t        t	        j                  |            dx}x}}| ||dz    }d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }	t	        j                  d|dd       dz   d|	iz  }
t        t	        j                  |
            dx}}d}||v}|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }	t	        j                  d|dd       dz   d|	iz  }
t        t	        j                  |
            dx}}y)u   
    Fix B 정적 검증: finish-task.sh lifecycle dispatch heredoc 호출 라인에
    fatal exit 1 패턴이 있어야 한다 (WARN echo 패턴은 없어야 함).
    r	   r
   r&   r   )z%(py0)s != -%(py3)s
marker_posr~   r   z
>assert %(py6)spy6Ni  zexit 1r   r   regionr   uG   Fix B 실패: lifecycle dispatch 영역에 `exit 1` 미존재.
region: i,  r   r   z2[WARN] stash-lifecycle dispatch failed (non-fatal)r   r   u]   Fix B 실패: 구 WARN echo 패턴이 lifecycle dispatch 영역에 여전히 존재.
region: )r   r   findr   r7   r8   r9   r:   r;   r<   r=   r@   rA   )r   r   rL   rH   rG   @py_format5@py_format7r   rP   r   rJ   s              r[   *test_static_fix_b_line1175_uses_fatal_exitr      s
   
 ##W#5D45JO!O:OOO:OOOOOO:OOO:OOO!OOO12K1NOOOOOOOO *j4/0F 8v  8v                 	$3<"	$     @ ?vM  ?v    @      HN    HN   	$3<"	$    r]   c                     ddl } t        j                  d      }| j                  d      }|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z   d|iz  }t        t        j                  |            dx}x}}| j                  d      }	|	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z   d|iz  }t        t        j                  |            dx}x}}y)u   
    task-2576 TODO-4 완료 후: `-x ... stash_audit.py` 패턴이 0건이어야 한다.
    (라인 42, 1145 모두 -f 로 교체 완료 — -x는 완전 제거)
    -f 가드는 정확히 3건이어야 한다 (line 42, 1145, 1166).
    r   Nr	   r
   z if\s+\[\s+-x\s+.*stash_audit\.pyr(   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   	x_matches)r   rc   r   r   uB   TODO-4 fix 후 `-x stash_audit.py` 가드가 0건이어야 하나 u   건 잔존.
matches: z
>assert %(py8)spy8z if\s+\[\s+-f\s+.*stash_audit\.py   	f_matchesu>   `if [ -f ... stash_audit.py ]` 가드 수 기대 3건, 실제 u   건.
matches: )rer   r   compilefindallr   r7   r8   r9   r:   r;   r<   r=   r@   rA   )r   content	x_patternr   rL   ro   rH   r   @py_format9	f_patternr   s              r[   ,test_static_x_guards_preserved_exactly_twicer   
  sr    &&&8G

>?I!!'*Iy> Q >Q   >Q                                MSQZ^L\ ];	      

>?I!!'*Iy> Q >Q   >Q                                IYHX Y;	      r]   )r   N)__doc__builtinsr9   _pytest.assertion.rewrite	assertionrewriter7   r0   r3   r,   pathlibr   __file__resolver_   WORKTREE_ROOTr   r   r\   rz   r   r   r    r]   r[   <module>r      s   (     X&&(003*-== B Dt DPT DVZt ZPT ZBD,r]   