
    (<ir                        d Z ddlZddlZddlZddlmZ ddlmZmZ ej                  j                  d e ee      j                  j                               ddlmZmZ d dededz  defd	Zd dededz  defd
Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      Z G d d      ZddlmZ  G d d      Z G d d      Z G d d      Zy)!u   헤임달(개발2팀 테스터): codex_gate_check 테스트 선행 작성 — TDD RED 단계.

대상: /home/jay/workspace/scripts/codex_gate_check.py
함수: codex_gate_check(task_file, affected_files, workspace_root) -> dict
    N)Path)	MagicMockpatch)codex_gate_check_maat_fallback_checkriskssuggestionsreturnc                 |    | |xs g d}t               }d|_        t        j                  |      |_        d|_        |S )u=   Codex CLI가 정상 반환하는 JSON stdout을 모킹한다.r   r	   r    r   
returncodejsondumpsstdoutstderrr   r	   payload	mock_procs       T/home/jay/workspace/.worktrees/task-2057-dev2/scripts/tests/test_codex_gate_check.py_make_codex_resultr      F     "(bG IIzz'*II    c                 |    | |xs g d}t               }d|_        t        j                  |      |_        d|_        |S )u=   마아트 폴백이 반환하는 JSON stdout을 모킹한다.r   r   r   r   r   s       r   _make_maat_resultr   %   r   r   c                       e Zd ZdZd Zd Zy)TestCodexPassNoCriticalu3   critical severity 리스크가 없으면 gate PASS.c                 
   t        |dz        }t        |      j                  d       dddddddd	dg}t        |d
g      }t	        d|      5  t        |dgd      }d d d        d   du sJ d       y # 1 sw Y   xY w)Ntask.md   # 설계 문서highu   성능 저하 가능성severitydescriptionmediumu   로그 누락 우려lowu   주석 부족u   캐시 레이어 추가 검토r	   subprocess.runreturn_value
src/api.py/home/jay/workspace	task_fileaffected_filesworkspace_rootpassTu!   critical 없으면 PASS여야 함strr   
write_textr   r   r   selftmp_pathr/   r   r   results         r   test_codex_pass_no_criticalz3TestCodexPassNoCritical.test_codex_pass_no_critical8   s    9,-	Y""#45  0IJ!2HI?

 'u;[:\]	#)< 	%# ,~4F	 f~%J'JJ%	 	s   A99Bc                     t        |dz        }t        |      j                  d       t        g g       }t	        d|      5  t        |g d      }ddd       d	   d
u sJ y# 1 sw Y   xY w)u#   리스크가 아예 없어도 PASS.r    u   # 빈 설계r   r)   r*   r-   r.   Nr2   Tr3   r7   r8   r/   r   r9   s        r   test_codex_pass_empty_risksz3TestCodexPassNoCritical.test_codex_pass_empty_risksL   sv    9,-	Y"">2&RR@	#)< 	%#!4F	 f~%%%	 	s   A$$A-N)__name__
__module____qualname____doc__r:   r=    r   r   r   r   5   s    =K(&r   r   c                       e Zd ZdZd Zd Zy)TestCodexFailCriticalExistsu;   critical severity 리스크가 1개 이상이면 gate FAIL.c                     t        |dz        }t        |      j                  d       ddddddg}t        |      }t	        d|	      5  t        |d
gd      }d d d        d   du sJ d       y # 1 sw Y   xY w)Nr    r!   criticalu   인증 우회 취약점r#   r&   u   로그 누락r)   r*   src/auth.pyr-   r.   r2   Fu%   critical 존재 시 FAIL이어야 함r3   r6   s         r   test_codex_fail_single_criticalz;TestCodexFailCriticalExists.test_codex_fail_single_criticalc   s    9,-	Y""#45 $4MN!/B
 'u-	#)< 	%# -4F	 f~&O(OO&	 	s   A22A;c                 ,   t        |dz        }t        |      j                  d       ddddddg}t        |      }t	        d|      5  t        |d	d
gd      }ddd       d   du sJ t        d |d   D              }|dk(  sJ y# 1 sw Y   /xY w)u   critical 2개: 여전히 FAIL.r       # 설계rF   u   SQL 인젝션r#   u   권한 상승 가능r)   r*   z	src/db.pyrG   r-   r.   Nr2   Fc              3   2   K   | ]  }|d    dk(  sd  yw)r$   rF      NrB   .0rs     r   	<genexpr>zQTestCodexFailCriticalExists.test_codex_fail_multiple_criticals.<locals>.<genexpr>   s     W11Z=J;VQWs   r      )r4   r   r5   r   r   r   sum)r7   r8   r/   r   r   r9   critical_counts          r   "test_codex_fail_multiple_criticalsz>TestCodexFailCriticalExists.test_codex_fail_multiple_criticalsv   s    9,-	Y"":. $OD#4JK
 'u-	#)< 	%# +];4F	 f~&&&WwWW"""	 	s   B

BN)r>   r?   r@   rA   rH   rT   rB   r   r   rD   rD   `   s    EP&#r   rD   c                       e Zd ZdZd Zd Zy)TestCodexTimeoutFallbackToMaatuU   subprocess.run이 TimeoutExpired를 발생시키면 마아트 폴백을 사용한다.c                     t        |dz        }t        |      j                  d       dddg}t        |dg      fd}t	        d	|
      5  t        |dgd      }d d d        d   dk(  sJ y # 1 sw Y   xY w)Nr    r!   r'   u   폴백 경고r#   u   마아트 제안r(   c                      | r| d   n|j                  dg       }t        d |D              rt        j                  |d      S )Nr   argsc              3   6   K   | ]  }d t        |      v   ywcodexNr4   rN   cs     r   rP   zjTestCodexTimeoutFallbackToMaat.test_codex_timeout_fallback_to_maat.<locals>.side_effect.<locals>.<genexpr>        27c!f$2      cmdtimeoutgetany
subprocessTimeoutExpiredrY   kwargsrd   	maat_procs      r   side_effectzWTestCodexTimeoutFallbackToMaat.test_codex_timeout_fallback_to_maat.<locals>.side_effect   sB    !$q'vzz&"'=C2c22 //CDDr   r)   rn   zsrc/service.pyr-   r.   sourcemaat_fallback)r4   r   r5   r   r   r   )r7   r8   r/   
maat_risksrn   r9   rm   s         @r   #test_codex_timeout_fallback_to_maatzBTestCodexTimeoutFallbackToMaat.test_codex_timeout_fallback_to_maat   s    9,-	Y""#45 $)IJ
%j?Q>RS		 #= 	%# 014F	 h?222	 	s   A33A<c                 $   t        |dz        }t        |      j                  d       t        g g       fd}t	        d|      5  t        |g d      }d	d	d	       h d
}|j                  j                               sJ y	# 1 sw Y   /xY w)uP   타임아웃 폴백 결과도 유효한 딕셔너리 구조를 가져야 한다.r    rJ   r(   c                      | r| d   n|j                  dg       }t        d |D              rt        j                  |d      S )Nr   rY   c              3   6   K   | ]  }d t        |      v   ywr[   r]   r^   s     r   rP   ziTestCodexTimeoutFallbackToMaat.test_codex_timeout_result_is_valid.<locals>.side_effect.<locals>.<genexpr>   r`   ra   rb   rc   rf   rk   s      r   rn   zVTestCodexTimeoutFallbackToMaat.test_codex_timeout_result_is_valid.<locals>.side_effect   sB    !$q'vzz&"'=C2c22 //CDDr   r)   ro   r-   r.   N>   r2   errorr   rp   r	   )r4   r   r5   r   r   r   issubsetkeys)r7   r8   r/   rn   r9   required_keysrm   s         @r   "test_codex_timeout_result_is_validzATestCodexTimeoutFallbackToMaat.test_codex_timeout_result_is_valid   s    9,-	Y"":.%bb9		 #= 	%#!4F	 L%%fkkm444	 	s   	BBN)r>   r?   r@   rA   rs   r{   rB   r   r   rV   rV      s    _305r   rV   c                       e Zd ZdZd Zd Zy)TestCodexApiErrorFallbackToMaatuV   Codex CLI가 비정상 종료(returncode != 0)하면 마아트 폴백을 사용한다.c                    t        |dz        }t        |      j                  d       t               d_        d_        d_        t               d_        t        j                  ddg ii      _        d_        fd	}t        d
|      5  t        |dgd      }d d d        d   dk(  sJ y # 1 sw Y   xY w)Nr    rJ   rL   r   zAPI rate limit exceededr   blast_radiuscallersc                  b    | r| d   n|j                  dg       }t        d |D              rS S )Nr   rY   c              3   6   K   | ]  }d t        |      v   ywr[   r]   r^   s     r   rP   zmTestCodexApiErrorFallbackToMaat.test_codex_api_error_fallback_to_maat.<locals>.side_effect.<locals>.<genexpr>   r`   ra   )rg   rh   )rY   rl   rd   ast_proc
error_procs      r   rn   zZTestCodexApiErrorFallbackToMaat.test_codex_api_error_fallback_to_maat.<locals>.side_effect   s4    !$q'vzz&"'=C2c22!!Or   r)   ro   r,   r-   r.   rp   rq   )r4   r   r5   r   r   r   r   r   r   r   r   )r7   r8   r/   rn   r9   r   r   s        @@r   %test_codex_api_error_fallback_to_maatzETestCodexApiErrorFallbackToMaat.test_codex_api_error_fallback_to_maat   s    9,-	Y"":. [
 !

5
 ;**ny"o%FG	 #= 	%# ,~4F	 h?222	 	s   B66B?c                    t        |dz        }t        |      j                  d       t               }d|_        d|_        d|_        t        d|      5  t        |g d	      }d
d
d
       d   dk(  sJ |d   J y
# 1 sw Y   xY w)uk  API 오류 시 마아트 폴백으로 전환되며 source='maat_fallback'이어야 한다.

        구현체는 returncode != 0이면 즉시 _maat_fallback_check()를 호출한다.
        마아트 폴백 결과의 error 필드는 None으로 설정된다(폴백 자체는 성공).
        대신 source='maat_fallback'으로 오류 전환을 알린다.
        r    rJ   rL   r   zconnection refusedr)   r*   r-   r.   Nrp   rq   rw   	r4   r   r5   r   r   r   r   r   r   )r7   r8   r/   r   r9   s        r   %test_codex_api_error_sets_error_fieldzETestCodexApiErrorFallbackToMaat.test_codex_api_error_sets_error_field   s     9,-	Y"":.[
 !

0
 #*= 	%#!4F	 h?222g&&&	 	s   A>>BN)r>   r?   r@   rA   r   r   rB   r   r   r}   r}      s    `3B'r   r}   c                   H    e Zd ZdZh dZd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zy)TestOutputJsonFormatuB   반환 딕셔너리가 명세된 스키마를 충족해야 한다.>   r2   rw   r   rp   r	   c                 h   t        |dz        }t        |      j                  d       t        g       }t	        d|      5  t        |dgd      }d d d        | j                  j                  j                               s%J d| j                  |j                         z
          y # 1 sw Y   XxY w)	Nr    rJ   r)   r*   zsrc/main.pyr-   r.   u   누락 키: )	r4   r   r5   r   r   r   REQUIRED_KEYSrx   ry   r<   s        r   test_all_required_keys_presentz3TestOutputJsonFormat.test_all_required_keys_present  s    9,-	Y"":.&r*	#)< 	%# -4F	 !!**6;;=9n\$J\J\_e_j_j_lJlIm;nn9	 	s   B((B1c                     t        |dz        }t        |      j                  d       t        g       }t	        d|      5  t        |g d      }d d d        t        d   t              sJ y # 1 sw Y   xY w)Nr    rJ   r)   r*   r-   r.   r2   )r4   r   r5   r   r   r   
isinstanceboolr<   s        r   test_pass_is_boolz&TestOutputJsonFormat.test_pass_is_bool  sv    9,-	Y"":.&r*	#)< 	%#!4F	 &.$///	 	s   A..A7c                     t        |dz        }t        |      j                  d       t        dddg      }t	        d|      5  t        |dgd	
      }d d d        t        d   t              sJ y # 1 sw Y   xY w)Nr    rJ   r"   u   경고r#   r)   r*   zsrc/x.pyr-   r.   r   r4   r   r5   r   r   r   r   listr<   s        r   test_risks_is_listz'TestOutputJsonFormat.test_risks_is_list-  s    9,-	Y"":.&VH(U'VW	#)< 	%# *|4F	 &/4000	 	s   A33A<c                     t        |dz        }t        |      j                  d       t        g ddg      }t	        d|      5  t        |g d	      }d d d        t        d
   t              sJ y # 1 sw Y   xY w)Nr    rJ   u   제안 1u   제안 2r(   r)   r*   r-   r.   r	   r   r<   s        r   test_suggestions_is_listz-TestOutputJsonFormat.test_suggestions_is_list<  s~    9,-	Y"":.&r
J7OP	#)< 	%#!4F	 &/666	 	s   A22A;c                     t        |dz        }t        |      j                  d       t        g       }t	        d|      5  t        |g d      }ddd       d   d	k(  sJ y# 1 sw Y   xY w)
u2   Codex 정상 응답 시 source는 codex_companion.r    rJ   r)   r*   r-   r.   Nrp   codex_companionr3   r<   s        r   test_source_is_codex_on_successz4TestOutputJsonFormat.test_source_is_codex_on_successK  sv    9,-	Y"":.&r*	#)< 	%#!4F	 h#4444	 	s   A##A,c                     t        |dz        }t        |      j                  d       t        g       }t	        d|      5  t        |g d      }ddd       d   J y# 1 sw Y   xY w)	u   정상 응답 시 error=None.r    rJ   r)   r*   r-   r.   Nrw   r3   r<   s        r   test_error_is_none_on_successz2TestOutputJsonFormat.test_error_is_none_on_success[  sr    9,-	Y"":.&r*	#)< 	%#!4F	 g&&&	 	s   A  A)c                     t        |dz        }t        |      j                  d       ddddddg}t        |      }t	        d|	      5  t        |d
gd      }ddd       d   D ]  }d|v sJ d       d|v rJ d        y# 1 sw Y   *xY w)uB   리스크 항목은 severity, description 키를 가져야 한다.r    rJ   r"   u   고위험 항목r#   r'   u   저위험 항목r)   r*   zsrc/y.pyr-   r.   Nr   r$   u"   risk 항목에 severity 키 없음r%   u%   risk 항목에 description 키 없음r3   )r7   r8   r/   r   r   r9   items          r   +test_risk_item_has_severity_and_descriptionz@TestOutputJsonFormat.test_risk_item_has_severity_and_descriptionk  s    9,-	Y"":.  0BC/AB
 'u-	#)< 	%# *|4F	 7O 	RD%K'KK% D(Q*QQ(	R	 	s   BBc                 4   t        |dz        }t        |      j                  d       h d}ddddddd	d
ddddg}t        |      }t	        d|      5  t        |dgd      }ddd       d   D ]  }|d   |v rJ d|d            y# 1 sw Y   (xY w)u=   severity는 critical|high|medium|low 중 하나여야 한다.r    rJ   >   r'   r"   r&   rF   rF   u   치명r#   r"   u   높음r&   u   중간r'   u   낮음r)   r*   zsrc/z.pyr-   r.   Nr   r$   u"   허용되지 않는 severity 값: r3   )r7   r8   r/   valid_severitiesr   r   r9   r   s           r   test_severity_values_are_validz3TestOutputJsonFormat.test_severity_values_are_valid  s    9,-	Y"":.@#H=9!(;x8	
 'u-	#)< 	%# *|4F	 7O 	qD
#'77p;]^bcm^n]o9pp7	q	 	s   BBN)r>   r?   r@   rA   r   r   r   r   r   r   r   r   r   rB   r   r   r   r   
  s5    LGMo0175 ' R,qr   r   c                   D    e Zd ZdZh dZddZd Zd Zd Zd Z	d	 Z
d
 Zy)"TestMaatFallbackReturnsValidResultuV   마아트 폴백 경로에서도 완전한 result 딕셔너리를 반환해야 한다.>   r2   rw   r   rp   r	   Nc           
         t        |dz        }t        |      j                  d       t               }d|_        d|_        d|_        t        d|      5  t        dt        d	 |D               ||xs g d
dd      5  t        |g d      cddd       cddd       S # 1 sw Y   nxY w	 ddd       y# 1 sw Y   yxY w)uL  Codex 오류를 유발하여 마아트 폴백을 강제하는 헬퍼.

        마아트 폴백은 파일 존재 여부를 직접 검사하므로 affected_files는
        실제 존재하는 파일만 넘기거나 빈 목록을 사용한다.
        task_file은 tmp_path 안에 생성하여 실제로 존재하게 한다.
        r    rJ   rL   r   zcodex unavailabler)   r*   z%codex_gate_check._maat_fallback_checkc              3   ,   K   | ]  }|d    dk(    yw)r$   rF   NrB   rM   s     r   rP   zJTestMaatFallbackReturnsValidResult._force_maat_fallback.<locals>.<genexpr>  s     #TAAjMZ$?#Ts   rq   N)r2   r   r	   rp   rw   r-   r.   )
r4   r   r5   r   r   r   r   r   rh   r   )r7   r8   rr   maat_suggestionsr/   r   s         r   _force_maat_fallbackz7TestMaatFallbackReturnsValidResult._force_maat_fallback  s     9,-	Y"":.[
 !

/
#*= 	7 ##T#T TT'#3#9r-!	  ('#%#8 	 	  	 	 	s$   )B5>B	B5B(	$B55B>c                     | j                  |g       }| j                  j                  |j                               sJ y )Nrr   )r   r   rx   ry   r7   r8   r9   s      r   (test_maat_fallback_has_all_required_keyszKTestMaatFallbackReturnsValidResult.test_maat_fallback_has_all_required_keys  s7    **8*C!!**6;;=999r   c                 >    | j                  |g       }|d   dk(  sJ y )Nr   rp   rq   r   r   s      r   *test_maat_fallback_source_is_maat_fallbackzMTestMaatFallbackReturnsValidResult.test_maat_fallback_source_is_maat_fallback  s*    **8*Ch?222r   c                 H    dddg}| j                  ||      }|d   du sJ y)u2   마아트 폴백에서도 critical 없으면 PASS.r"   u   마아트 고위험r#   r   r2   TNr   r7   r8   rr   r9   s       r   -test_maat_fallback_pass_true_when_no_criticalzPTestMaatFallbackReturnsValidResult.test_maat_fallback_pass_true_when_no_critical  s7    #):OPQ
**8
*Kf~%%%r   c                 H    dddg}| j                  ||      }|d   du sJ y)u/   마아트 폴백에서 critical 있으면 FAIL.rF   u   마아트 치명 오류r#   r   r2   FNr   r   s       r   +test_maat_fallback_pass_false_when_criticalzNTestMaatFallbackReturnsValidResult.test_maat_fallback_pass_false_when_critical  s7    #->WXY
**8
*Kf~&&&r   c                 d    ddddddg}| j                  ||      }t        |d         dk(  sJ y	)
uJ   마아트 폴백 리스크 목록이 결과에 그대로 담겨야 한다.r&   u   마아트 중간 위험r#   r'   u   마아트 낮은 위험r   r   rQ   Nr   lenr   s       r   "test_maat_fallback_risks_preservedzETestMaatFallbackReturnsValidResult.test_maat_fallback_risks_preserved  sK     "2KL/HI

 **8
*K6'?#q(((r   c                 ^    g }ddg}| j                  |||      }t        |d         dk(  sJ y)u=   마아트 폴백 제안 목록이 결과에 담겨야 한다.u   마아트 제안 Au   마아트 제안 B)rr   r   r	   rQ   Nr   )r7   r8   rr   r   r9   s        r   (test_maat_fallback_suggestions_preservedzKTestMaatFallbackReturnsValidResult.test_maat_fallback_suggestions_preserved  sC    
02FG**8
]m*n6-()Q...r   N)r>   r?   r@   rA   r   r   r   r   r   r   r   r   rB   r   r   r   r     s.    `GM@:3&')/r   r   c                       e Zd ZdZd Zd Zy)TestCallersContextu?   _get_callers_context가 프롬프트에 통합되는지 검증.c                   	 t        |dz        }t        |      j                  d       |dz  }|j                          |dz  j                  d       t	               d_        t        j                  ddd	gd
dgdgddd      _        d_	        t        g g       	ddig 	fd}t        d|      5  t        |dgt        |            }ddd       d   du sJ t        d D              sJ y# 1 sw Y   'xY w)uI   AST callers 컨텍스트가 Codex 프롬프트에 포함되어야 한다.r    r!   scriptsast_dependency_map.py# dummyr   r,   zserver.py:42zroutes.py:15	server.pyz	routes.pyztest_api.py   )r   direct_importers
test_filestotal_affectedchanged_filer   r   r(   nc                      dxx   dz  cc<   | r| d   n|j                  dg       }t        d |D              rS |j                  dd      }j                  |       S )Nr   rL   r   rY   c              3   6   K   | ]  }d t        |      v   yw)ast_dependency_mapNr]   r^   s     r   rP   zbTestCallersContext.test_callers_context_included_in_prompt.<locals>.side_effect.<locals>.<genexpr>  s     ?a'3q61?ra   inputr   )rg   rh   append)rY   rl   rd   stdin_input
ast_result
call_countcaptured_inputscodex_results       r   rn   zOTestCallersContext.test_callers_context_included_in_prompt.<locals>.side_effect  sa    sOq O!$q'vzz&"'=C?3??!! **Wb1K"";/r   r)   ro   r.   Nr2   Tc              3   6   K   | ]  }d t        |      v   yw)	   호출됨Nr]   )rN   inps     r   rP   zMTestCallersContext.test_callers_context_included_in_prompt.<locals>.<genexpr>!  s     Fs;#c(*Fra   )r4   r   r5   mkdirr   r   r   r   r   r   r   r   r   rh   )
r7   r8   r/   scripts_dirrn   r9   r   r   r   r   s
         @@@@r   'test_callers_context_included_in_promptz:TestCallersContext.test_callers_context_included_in_prompt  s&   9,-	Y""#45 *	.	.::9E [
 !
 JJ , .?)4k(B#0/&'	!


 
 *""=1X
		  #= 	%# ,~"8}F	 f~%%%FoFFFF	 	s   =C<<Dc                     t        |dz        }t        |      j                  d       t        g g       }t	        d|      5  t        |dgd      }d	d	d	       d
v sJ d|v sJ y	# 1 sw Y   xY w)uQ   AST 스크립트 실패 시에도 codex_gate_check는 정상 동작해야 한다.r    r!   r(   r)   r*   znonexistent.py/tmp/nonexistentr.   Nr2   rp   r3   )r7   r8   r/   r   r9   s        r   ,test_callers_context_fallback_on_ast_failurez?TestCallersContext.test_callers_context_fallback_on_ast_failure#  s    9,-	Y""#45 *""=#,? 	%# 011F	 6!!!	 	s   A((A1N)r>   r?   r@   rA   r   r   rB   r   r   r   r     s    I4Gl"r   r   _get_callers_contextc                   "    e Zd ZdZd Zd Zd Zy)TestGetCallersContextu4   _get_callers_context 헬퍼 함수 단위 테스트.c                 ,    t        dgd      }|dk(  sJ y)u3   AST 스크립트가 없으면 빈 문자열 반환.r,   r   r   Nr   )r7   r9   s     r   %test_returns_empty_when_no_ast_scriptz;TestGetCallersContext.test_returns_empty_when_no_ast_script@  s    %|n6HI||r   c                    |dz  }|j                          |dz  j                  d       |dz  }|j                  d       t        j                  ddgdgg dd	d
      }t	               }d|_        ||_        d|_        t        d|      5  t        t        |      gt        |            }ddd       dv sJ d|v sJ y# 1 sw Y   xY w)u5   AST 호출 성공 시 호출 관계 문자열 반환.r   r   r   api.pyzdef get_data():
    pass
r   zserver.py:10rQ   )r   r   r   r   r   r   r   r)   r*   Nr   )r   r5   r   r   r   r   r   r   r   r   r4   )r7   r8   r   api_file
ast_outputr   r9   s          r   test_returns_context_on_successz5TestGetCallersContext.test_returns_context_on_successE  s     *	.	.::9E h&9: ZZ ()4 ./"$&'	!


 K	 	%		#)< 	J)3x=/3x=IF	J f$$$'''		J 	Js    C  C	c                    |dz  }|j                          |dz  j                  d       t               }d|_        d|_        d|_        t        d|      5  t        d	gt        |            }d
d
d
       dk(  sJ y
# 1 sw Y   xY w)u+   AST 호출 실패 시 빈 문자열 반환.r   r   r   rL   r   rw   r)   r*   r   N)	r   r5   r   r   r   r   r   r   r4   )r7   r8   r   r   r9   s        r   test_returns_empty_on_ast_errorz5TestGetCallersContext.test_returns_empty_on_ast_errorh  s    *	.	.::9EK	 		"	#)< 	E)8*c(mDF	E ||	E 	Es   A==BN)r>   r?   r@   rA   r   r   r   rB   r   r   r   r   =  s    >
!(Fr   r   c                   "    e Zd ZdZd Zd Zd Zy)TestCodexCascadeuC   3단계 캐스케이드(companion → exec → maat) 동작 검증.c                 "   t        |dz        }t        |      j                  d       t        g       }t	        d|      5  t	        dd      5  t        |g d      }d	d	d	       d	d	d	       d
   dk(  sJ y	# 1 sw Y   xY w# 1 sw Y    xY w)u4   codex-companion 성공 시 source='codex_companion'.r    rJ   r)   r*   zcodex_gate_check.os.path.isfileTr-   r.   Nrp   r   r3   r<   s        r   5test_companion_success_returns_codex_companion_sourcezFTestCodexCascade.test_companion_success_returns_codex_companion_source  s    9,-	Y"":.&r*	#)< 	8tL )'K`	
 h#4444	 	 	s$   BA9B9B	>BBc                    t        |dz        }t        |      j                  d       t               }d|_        d|_        d|_        t        d|      5  t        |g d	      }d
d
d
       d   dk(  sJ y
# 1 sw Y   xY w)u3   companion 실패 시 마아트 폴백으로 전환.r    rJ   rL   r   zcompanion errorr)   r*   r-   r.   Nrp   rq   r   r7   r8   r/   	fail_procr9   s        r   &test_companion_fail_falls_back_to_maatz7TestCodexCascade.test_companion_fail_falls_back_to_maat  s    9,-	Y"":.K	 		,	#)< 	%#BG\F	 h?222		 	   A77B c                    t        |dz        }t        |      j                  d       t               }d|_        d|_        d|_        t        d|      5  t        |g d	      }d
d
d
       d   dk(  sJ y
# 1 sw Y   xY w)u.   companion, exec 모두 실패 시 maat 폴백.r    rJ   rL   r   rw   r)   r*   r-   r.   Nrp   rq   r   r   s        r   *test_both_codex_fail_returns_maat_fallbackz;TestCodexCascade.test_both_codex_fail_returns_maat_fallback  s    9,-	Y"":.K	 		"	#)< 	%#BG\F	 h?222		 	r   N)r>   r?   r@   rA   r   r   r   rB   r   r   r   r   |  s    M
53 3r   r   c                   "    e Zd ZdZd Zd Zd Zy)TestMaatFallbackEnhancedu&   마아트 폴백 강화 기능 검증.c                    t        |dz        }t        |      j                  d       g }t        d      D ]9  }|d| dz  }|j                  d|        |j	                  t        |             ; t        ||t        |            }|d   D cg c]  }|d   d	k(  sd
|d   v s| }}t        |      dk\  sJ yc c}w )u7   affected_files 6개 이상이면 high 리스크 경고.r    r!      filez.pyz# file r   r$   r"   u   변경 범위r%   rL   N)r4   r   r5   ranger   r   r   )	r7   r8   r/   filesifr9   rO   
high_riskss	            r   test_large_scope_warningz1TestMaatFallbackEnhanced.test_large_scope_warning  s    9,-	Y""#45q 	!AT!C=(ALL71#'LLQ 	!
 &iHF!'tAAjMV4KP_cdercsPsat
t:!### us   B<B<%B<c                     t        |dz        }t        |      j                  d       t        |g t        |            }|d   D cg c]  }|d   dk(  sd|d   v s| }}t	        |      dk\  sJ y	c c}w )
uA   task_file에 보안 민감 키워드 포함 시 medium 리스크.r    u@   # 인증 모듈 변경
보안 취약점 수정 및 API키 갱신r   r$   r&   u   보안 민감 키워드r%   rL   Nr4   r   r5   r   r   r7   r8   r/   r9   rO   medium_riskss         r   test_security_keyword_detectionz8TestMaatFallbackEnhanced.test_security_keyword_detection  s    9,-	Y""#fg%iS]C#)'?  Caa
mx6OTmqr  tA  rB  UB  C  C< A%%% Cs   A3A3A3c                     t        |dz        }t        |      j                  d       t        |g t        |            }|d   D cg c]  }|d   dk(  s| }}t	        |      dk(  sJ yc c}w )uH   보안 키워드 없는 일반 task에서는 medium 리스크 미생성.r    u$   # 로깅 개선
로그 포맷 변경r   r$   r&   r   Nr  r  s         r   $test_no_false_positive_on_clean_taskz=TestMaatFallbackEnhanced.test_no_false_positive_on_clean_task  sq    9,-	Y""#JK%iS]C#)'?Paa
mx6OPP< A%%% Qs   A+A+N)r>   r?   r@   rA   r   r  r  rB   r   r   r   r     s    0$&&r   r   r   )rA   r   ri   syspathlibr   unittest.mockr   r   pathinsertr4   __file__parentr   r   r   r   r   r   rD   rV   r}   r   r   r   r   r   r   r   rB   r   r   <module>r     s      
  * 3tH~,,334 5 C
d 
 
	 

T 
t 
y 
 %& %&V*# *#`05 05l>' >'HMq MqfG/ G/ZJ" J"` 29 9~-3 -3f"& "&r   