
     jY                       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 ddlmZ ddlZ ee      j%                         j&                  j&                  j&                  Z ee      ej,                  v r!ej,                  j/                   ee             ej,                  j1                  d ee             ddlmZmZmZ ddlmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z. dZ/d	Z0d
Z1ejd                  d'd       Z3d(dZ4d)dZ5d)dZ6d)dZ7d)dZ8d)dZ9d)dZ:d)dZ;d)dZ<d)dZ=d)dZ>d)dZ?d Z@d)dZAd ZBd ZCd ZDd ZEd ZFd ZGd  ZHd)d!ZId" ZJd# ZKd$ ZLd% ZMd& ZNy)*u/  tests/regression/test_cron_session_safety_guard_2526.py

회귀 테스트 — task-2526 cron ``--session`` safety guard / safe_cron_dispatch wrapper.

회장 §본질 (2026-05-10):
  독립 bot task cron에 ``--session`` 옵션이 잘못 붙어 봇이 아니라 **아누 자기 세션이
  resume된 사고**가 발생함. 본 테스트는 이 사고를 회귀 fixture로 박제하여 동일 사고가
  다시 발생하지 못하도록 wrapper preflight를 강제한다.

회장 §명시 6 회귀 검증 (정확히 6개):
  1. independent_task + ``--session`` → BLOCK
  2. merge_task + ``--session`` → BLOCK
  3. followup_readonly + ``--session`` → ALLOW
  4. bot_task + bot_key + no ``--session`` → ALLOW
  5. bot_task + no bot_key → BLOCK
  6. owner_pat fallback 감지 → BLOCK

본 사건 fixture (PR #74 재위임 오류):
  - 잘못된 cron ``5C9995CCB`` — ``--session 5eee7634-b0be-4594-b84e-311ae64e557b`` 동반
    → wrapper가 BLOCK 했어야 함 (본 테스트가 박제)
  - 재발사 cron ``74325894`` — ``--session`` 빼고 발사 → 정상 (본 테스트가 ALLOW 박제)

회장 §보안:
  - raw token / raw key / raw session UUID 정적 검사 (wrapper 출력에 0 노출)
  - subprocess 실행 X (preflight only)
  - audit JSONL은 tmp_path에만 기록 (production audit-jsonl 오염 X)
    )annotationsN)asdict)Path)DispatchStatussafe_cron_dispatchformat_chairman_block_notice)ACTOR_ANU_SESSIONACTOR_BOT_SESSIONBlockedReasonCronTargetingAuditRecordREQUIRED_AUDIT_FIELDS_2526SUPPLEMENTARY_AUDIT_FIELDS_2526TASK_KIND_BOTTASK_KIND_FOLLOWUP_ROTASK_KIND_INDEPENDENTTASK_KIND_MERGEbuild_audit_recorddetect_misrouted_sessionensure_no_raw_secretsevidence_based_recoverhash_bot_keysanitize_command_previewsoft_kill_misrouted
69370320120b94683120a691cfz$5eee7634-b0be-4594-b84e-311ae64e557bc                    | dz  S )u<   production audit-jsonl 오염 방지 — tmp_path에 격리.zcron-targeting-audit.jsonl )tmp_paths    K/home/jay/workspace/tests/regression/test_cron_session_safety_guard_2526.py
audit_pathr    Q   s     222    c                    | j                         sg S | j                  d      j                         D cg c](  }|j                         st	        j
                  |      * c}S c c}w )u>   audit JSONL 파일의 모든 line을 dict 리스트로 반환.utf-8)exists	read_text
splitlinesstripjsonloads)r    lns     r   _read_audit_linesr+   W   sO    	%/%9%9'%B%M%M%O^rSUS[S[S]DJJrN^^^s   A$
A$c           	        t        ddt        t        t        t        |       }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                   }t"        j$                  }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j&                  }t)               }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }t        j*                  d      dz   d
|iz  }t        t        j                  |            dx}x}}|j,                  }d}||u}|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}}g }d}|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                  |      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  }d&d'|iz  }t        t        j                  |            dx}
x}x}x}x}x}x}}t3        |       }t5        |      }d%}||k(  }|st        j                  d|fd(||f      d)t        j                         v st        j                  t4              rt        j                  t4              nd)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,   }|d-   }
|
t        k(  }|st        j                  d|fd.|
t        f      t        j                  |
      d/t        j                         v st        j                  t              rt        j                  t              nd/d0z  }d1d2|iz  }t        t        j                  |            dx}
}|d3   }
d4}|
|u }|slt        j                  d5|fd6|
|f      t        j                  |
      t        j                  |      d7z  }d8d9|iz  }t        t        j                  |            dx}
x}}|d:   }
d;}|
|u }|slt        j                  d5|fd6|
|f      t        j                  |
      t        j                  |      d7z  }d8d9|iz  }t        t        j                  |            dx}
x}}|d<   }
t"        j$                  }|
|k(  }|st        j                  d|fd=|
|f      t        j                  |
      dt        j                         v st        j                  t"              rt        j                  t"              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}
x}}y)>uO   본 사건 cron 5C9995CCB — independent dev3 task에 anu self-session 동반.z)dev3-team independent_task: rebuild stats2mpromptschedulechattarget_bot_key	task_kind
session_idr    ==zK%(py2)s
{%(py2)s = %(py0)s.status
} == %(py6)s
{%(py6)s = %(py4)s.BLOCKED
}resultr   py0py2py4py6assert %(py8)spy8Nzi%(py2)s
{%(py2)s = %(py0)s.blocked_reason
} == %(py6)s
{%(py6)s = %(py4)s.INDEPENDENT_TASK_WITH_SESSION
}r   zK%(py2)s
{%(py2)s = %(py0)s.command_argv
} == %(py6)s
{%(py6)s = %(py4)s()
}tupleu&   BLOCK시 command_argv는 비어야 함
>assert %(py8)sis not)z;%(py2)s
{%(py2)s = %(py0)s.chairman_notice
} is not %(py5)sr:   r;   py5assert %(py7)spy7CRON_TARGETING_GUARD_BLOCKEDin)z7%(py1)s in %(py5)s
{%(py5)s = %(py3)s.chairman_notice
}py1py3rG   anu_sessionsession)z6%(py3)s in %(py7)s
{%(py7)s = %(py5)s.blocked_reason
})rO   rG   rI   %(py9)spy9)z:%(py12)s in %(py16)s
{%(py16)s = %(py14)s.blocked_reason
})py12py14py16z%(py18)spy18   zassert %(py21)spy21z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenlinesr:   rN   rO   r=   r   r3   z%(py1)s == %(py3)sr   rN   rO   assert %(py5)srG   session_id_presentTisz%(py1)s is %(py4)srN   r<   assert %(py6)sr=   session_id_allowedFblocked_reason)zE%(py1)s == %(py5)s
{%(py5)s = %(py3)s.INDEPENDENT_TASK_WITH_SESSION
})r   
CHAIR_CHATDEV3_DAGDA_KEYr   ANU_SELF_SESSION_UUIDstatusr   BLOCKED
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationrh   r   INDEPENDENT_TASK_WITH_SESSIONcommand_argvrB   _format_assertmsgchairman_noticeappend_format_boolopr+   r[   )r    r8   @py_assert1@py_assert5@py_assert3@py_format7@py_format9@py_assert4@py_format6@py_format8@py_assert0@py_assert2@py_assert6@py_assert11@py_assert15@py_assert13@py_format10@py_format17@py_format19@py_format20@py_format22r\   rec@py_format4@py_format5s                            r   6test_regression_1_independent_task_with_session_blocksr   b   s   :%'(F ==2N222=22222=222222262226222=222222N222N22222222222  OM$O$OO $OOOOO $OOOOOOO6OOO6OOO OOOOOOMOOOMOOO$OOOOOOOOS%'S')SSS'SSSSSS6SSS6SSSSSSSSS%SSS%SSS'SSS+SSSSSSSS!!--!----!------6---6---!----------)CV-C-CC)-CCCCC)-CCCC)CCCCCCVCCCVCCC-CCCCCCCCW=WF11W=11WYW&BWBWWYBW5WWWWW=1WWW=WWWWWWFWWWFWWW1WWWWWWWYBWWWWYWWWWWW&WWW&WWWBWWWWWWWWWWWWWWWj)Eu::?:33uu:
(C{4444444444444444444444444444#$,,$,,,,$,,,$,,,,,,,,,,#$--$----$---$---------- OM$O$OO $OOOOO $OOOO OOOOOOMOOOMOOO$OOOOOOOOr!   c           	        t        ddt        t        t        t        |       }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}|j                   }t"        j$                  t"        j&                  f}||v }|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(                  }t+               }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}}y)u5   PR merge 위임에 anu self-session 동반 → BLOCK.uO   [task-2526] merge PR #74 — gh pr merge 74 --squash GH_TOKEN=$BOT_GITHUB_TOKENz	0 9 * * 1r.   r5   r7   r8   r   r9   r>   r?   NrK   )z6%(py2)s
{%(py2)s = %(py0)s.blocked_reason
} in %(py5)srF   rH   rI   rA   rB   )r   ri   rj   r   rk   rl   r   rm   rn   ro   rp   rq   rr   rs   rt   ru   rh   r   MERGE_TASK_WITH_SESSIONTARGET_SESSION_OWNER_MISMATCHrw   rB   
r    r8   r|   r}   r~   r   r   r   r   r   s
             r   0test_regression_2_merge_task_with_session_blocksr      s   `%!(F ==2N222=22222=222222262226222=222222N222N22222222222   --33%   %     %              !   %       )%')'))))'))))))6)))6)))))))))%)))%)))')))))))r!   c           	        t        ddt        dt        t        |       }|j                  }t
        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }d}||u }|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                   }|st        j"                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        t        j                  |
            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  }dd|iz  }	t        t        j                  |	            dx}x}}t%        |       }t'        |      }d}||k(  }|st        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  }d
d|iz  }t        t        j                  |            dx}x}}|d   }|d   }|t        k(  }|st        j                  d|fd|t        f      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$   }d%}||u }|slt        j                  d|fd&||f      t        j                  |      t        j                  |      d'z  }d(d)|iz  }t        t        j                  |            dx}x}}|d*   }d%}||u }|slt        j                  d|fd&||f      t        j                  |      t        j                  |      d'z  }d(d)|iz  }t        t        j                  |            dx}x}}|d+   }|t(        k(  }|st        j                  d|fd|t(        f      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-   }d}||u }|slt        j                  d|fd&||f      t        j                  |      t        j                  |      d'z  }d(d)|iz  }t        t        j                  |            dx}x}}y).uC   read-only status scan followup + 같은 chat anu session → ALLOW.u6   followup readonly: status scan only — no commit/push30mNr.   r5   zK%(py2)s
{%(py2)s = %(py0)s.status
} == %(py6)s
{%(py6)s = %(py4)s.ALLOWED
}r8   r   r9   r>   r?   rb   z6%(py2)s
{%(py2)s = %(py0)s.blocked_reason
} is %(py5)srF   rH   rI   ,   ALLOWED 시 command_argv가 채워져야 함2
>assert %(py2)s
{%(py2)s = %(py0)s.command_argv
}r:   r;   	--sessionrK   z4%(py1)s in %(py5)s
{%(py5)s = %(py3)s.command_argv
}rM   rX   rZ   r[   r\   r]   r   r3   r^   r   r_   r`   rG   ra   Trd   re   rf   r=   rg   actor_expectedr	   rh   )r   ri   r   rk   rl   r   ALLOWEDrn   ro   rp   rq   rr   rs   rt   ru   rh   rw   rx   r+   r[   r	   )r    r8   r|   r}   r~   r   r   r   r   r   @py_format3r   r   r\   r   r   r   s                    r   7test_regression_3_followup_readonly_with_session_allowsr      sS   G'(F ==2N222=22222=222222262226222=222222N222N22222222222  (D( D(((( D((((((6(((6((( (((D(((((((NNN NNNNNNN6NNN6NNNNNNNNN-&---;-----;----;------&---&-----------j)Eu::?:33uu:
(C{4444444444444444444444444444#$,,$,,,,$,,,$,,,,,,,,,,#$,,$,,,,$,,,$,,,,,,,,,, 5 $55555 $5555 555555$5555$55555555 (D( D(((( D((( (((D(((((((r!   c           	     ^   t        ddt        t        t        d|       }|j                  }t
        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }d}||u }|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                   }|st        j"                  d      dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }
t        t        j                  |
            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      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%        |       }|d   }|d   }t'        t              }||k(  }|st        j                  d|fd||f      t        j                  |      d t        j                         v st        j                  t&              rt        j                  t&              nd d!t        j                         v st        j                  t              rt        j                  t              nd!t        j                  |      d"z  }d
d|iz  }t        t        j                  |            dx}x}}|d#   }d$}||u }|slt        j                  d|fd%||f      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t        t        j                  |            dx}x}}|d)   }|t(        k(  }|st        j                  d|fd*|t(        f      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/   }d}||u }|slt        j                  d|fd%||f      t        j                  |      t        j                  |      d&z  }d'd(|iz  }t        t        j                  |            dx}x}}y)0uZ   재발사 cron 74325894 — --session 빼고 발사 → 정상 (다그다 trigger 박제).uU   [dev3-team] task-2526 — independent bot task, GH_TOKEN=$BOT_GITHUB_TOKEN gh pr viewr-   Nr.   r5   r   r8   r   r9   r>   r?   rb   r   rF   rH   rI   r   r   r   r   not inz8%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.command_argv
}rM   uO   bot_task에 session이 새어들어가면 본 사건 재발 — 절대 포함 Xz
>assert %(py7)sz--keyrK   r   r   target_bot_key_hash)z0%(py1)s == %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}r   rj   )rN   rO   r<   r=   ra   Frd   re   rf   r=   r   r^   r
   r_   r`   rG   rh   )r   ri   rj   r   rl   r   r   rn   ro   rp   rq   rr   rs   rt   ru   rh   rw   rx   r+   r   r
   )r    r8   r|   r}   r~   r   r   r   r   r   r   r   r   r\   r   r   r   s                    r   5test_regression_4_bot_task_with_key_no_session_allowsr      sf   f%F ==2N222=22222=222222262226222=222222N222N22222222222  (D( D(((( D((((((6(((6((( (((D(((((((NNN NNNNNNN6NNN6NNNNNNNNN f11 ;11  ;1          %    %    2    	Z     )f)))7)))))7))))7))))))f)))f)))))))))))j)E
(C$%En)EE%)EEEEE%)EEEE%EEEEEEEEEEEEEEEnEEEnEEE)EEEEEEEE#$--$----$---$---------- 5 $55555 $5555 555555$5555$55555555 (D( D(((( D((( (((D(((((((r!   c           	        t        ddt        dt        d|       }|j                  }t        j
                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }t        j                   }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j"                  }t%               }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)uA   merge cron + 회장 chat key만 (다그다 key 없음) → BLOCK.zK[task-2526] merge PR #74 GH_TOKEN=$BOT_GITHUB_TOKEN gh pr merge 74 --squashr-   Nr.   r5   r7   r8   r   r9   r>   r?   zh%(py2)s
{%(py2)s = %(py0)s.blocked_reason
} == %(py6)s
{%(py6)s = %(py4)s.BOT_KEY_MISSING_FOR_BOT_TASK
}r   rA   rB   )r   ri   r   rl   r   rm   rn   ro   rp   rq   rr   rs   rt   ru   rh   r   BOT_KEY_MISSING_FOR_BOT_TASKrw   rB   r    r8   r|   r}   r~   r   r   s          r   -test_regression_5_bot_task_without_key_blocksr      s   \!F ==2N222=22222=222222262226222=222222N222N22222222222  NM$N$NN $NNNNN $NNNNNNN6NNN6NNN NNNNNNMNNNMNNN$NNNNNNNN)%')'))))'))))))6)))6)))))))))%)))%)))')))))))r!   c           	        t        ddt        dt        d|       }|j                  }t        j
                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }t        j                   }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)u>   task_kind=bot_task + bot_key 누락도 BLOCK (cross-coverage).z;[dev3-team] independent bot task GH_TOKEN=$BOT_GITHUB_TOKENr-   Nr.   r5   r7   r8   r   r9   r>   r?   r   r   )r   ri   r   rl   r   rm   rn   ro   rp   rq   rr   rs   rt   ru   rh   r   r   r   s          r   3test_regression_5b_bot_task_without_key_also_blocksr      sR   LF ==2N222=22222=222222262226222=222222N222N22222222222  NM$N$NN $NNNNN $NNNNNNN6NNN6NNN NNNNNNMNNNMNNN$NNNNNNNNr!   c           	        t        ddt        t        t        d|       }|j                  }t
        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }t         j"                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j$                  }t'               }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)ua   gh pr merge 명령에 GH_TOKEN=$BOT_GITHUB_TOKEN 미설정 → owner_pat fallback path → BLOCK.uD   [task-2526] merge PR #74 — gh pr merge 74 --squash --delete-branchr-   Nr.   r5   r7   r8   r   r9   r>   r?   )zg%(py2)s
{%(py2)s = %(py0)s.blocked_reason
} == %(py6)s
{%(py6)s = %(py4)s.OWNER_PAT_FALLBACK_DETECTED
}r   rA   rB   )r   ri   rj   r   rl   r   rm   rn   ro   rp   rq   rr   rs   rt   ru   rh   r   OWNER_PAT_FALLBACK_DETECTEDrw   rB   r   s          r   +test_regression_6_owner_pat_fallback_blocksr      s   U%!	F ==2N222=22222=222222262226222=222222N222N22222222222  MM$M$MM $MMMMM $MMMMMMM6MMM6MMM MMMMMMMMMMMMMM$MMMMMMMM)%')'))))'))))))6)))6)))))))))%)))%)))')))))))r!   c           	        t        ddt        t        t        d|       }|j                  }t
        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}|j                  }d}||u }|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)uU   대조군 — bot token이 명시 주입되면 OWNER_PAT_FALLBACK_DETECTED는 끈다.uO   [task-2526] merge PR #74 — GH_TOKEN=$BOT_GITHUB_TOKEN gh pr merge 74 --squashr-   Nr.   r5   r   r8   r   r9   r>   r?   rb   r   rF   rH   rI   )r   ri   rj   r   rl   r   r   rn   ro   rp   rq   rr   rs   rt   ru   rh   r   s
             r   8test_regression_6b_owner_pat_safe_when_gh_token_injectedr     s*   `%!F ==2N222=22222=222222262226222=222222N222N22222222222  (D( D(((( D((((((6(((6((( (((D(((((((r!   c           	        t        ddt        t        t        t        |       }|j
                  }t        j                  }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }t        j                  d	      d
z   d|iz  }t        t        j                   |            dx}x}}|j"                  }t$        j&                  }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }dd|iz  }t        t        j                   |            dx}x}}y)u   본 사건: cron 5C9995CCB — dev3 다그다에게 위임하려 했는데 --session 5eee7634...
    가 붙어 있어서 PID 448820 = 아누 자기 세션이 resume되었음.

    본 wrapper는 이 cron을 **실행 전에** 차단해야 함.
    u/   [dev3-team] task-2526 발사 — gh pr merge 74r-   r.   r5   r7   r8   r   r9   u|   본 사건 cron 5C9995CCB가 wrapper에 의해 BLOCK되지 않으면 PR #74 재위임 오류가 다시 발생할 수 있음.rC   r?   Nr@   r   r>   )r   ri   rj   r   rk   rl   r   rm   rn   ro   rp   rq   rr   rs   rx   rt   ru   rh   r   rv   r   s          r   3test_pr74_misroute_incident_replay_blocks_5C9995CCBr   %  s     @%'(F == N22 =22   =2                    +    +    3   	B       OM$O$OO $OOOOO $OOOOOOO6OOO6OOO OOOOOOMOOOMOOO$OOOOOOOOr!   c           	        t        ddt        t        t        d|       }|j                  }t
        j                  }||k(  }|st        j                  d|fd||f      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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   재발사 cron 74325894 — --session 제거 후 정상 위임.

    다그다 PID 455634에서 trigger되어야 한다 (anu PID 448820 X).uL   [dev3-team] task-2526 재발사 — GH_TOKEN=$BOT_GITHUB_TOKEN gh pr view 74r-   Nr.   r5   r   r8   r   r9   r>   r?   r   r   r   rM   rH   rI   )r   ri   rj   r   rl   r   r   rn   ro   rp   rq   rr   rs   rt   ru   rw   )r    r8   r|   r}   r~   r   r   r   r   r   r   r   s               r   )test_pr74_redispatch_cron_74325894_allowsr   <  s,     ]%F ==2N222=22222=222222262226222=222222N222N222222222221f111;11111;1111;111111f111f11111111111r!   c           	        t        ddt        t        t        d|        t	        |       }t        |      }d}||k(  }|st        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  }dd|iz  }t        t        j                  |            dx}x}}|d   }t        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z   d|
iz  }t        t        j                  |            d}	 t         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z   d|
iz  }t        t        j                  |            d}	 t        t              }d}||k(  }|st        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                  t              rt        j                  t              ndt        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}y)uH   audit JSONL line에 회장 §4 명시 8 필드 + 2 보강 모두 존재.z0[dev3-team] task-2526 GH_TOKEN=$BOT_GITHUB_TOKENr-   Nr.   rX   r5   rZ   r[   r\   r]   r>   r?   r   rK   z%(py0)s in %(py2)sfnamer   r   zrequired audit field missing: 
>assert %(py4)sr<   z#supplementary audit field missing:    r   )r   ri   rj   r   r+   r[   rn   ro   rp   rq   rr   rs   rt   ru   r   rx   r   )r    r\   r   r}   r   r   r   r   r   r|   r   r   s               r   'test_audit_record_has_required_8_fieldsr   Q  sj   A% j)Eu::?:33uu:
(C+ F|EEEuEEEEEEuEEEuEEEEEEEEEEEEE=eWEEEEEEEF0 K|JJJuJJJJJJuJJJuJJJJJJJJJJJJJB5'JJJJJJJK )*/a/*a////*a//////3///3//////)///)///*///a///////r!   c                    t        d dt         t        d dt        t        d dt         dt         d 
      } t        | t              }|sd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	t        j                  |      d
z  }t        t        j                  |            d }t        |       }t        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  }dd|iz  }t        t        j                  |            d } | j"                  }t%        t              }||k(  }|s?t        j                   d|fd||f      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t        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|d   }
t        |
v}|st        j                   d|fdt        |
f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}}
y )Nchat=Fz#cokacdir --cron "x" --at 2m --chat  --key )
cron_id
target_botbot_keyr4   rg   r3   r   actor_actual_if_knowncommand_previewrh   z5assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstancer   r   )r:   rN   r;   r<   rK   r   r   dr   assert %(py4)sr<   r5   )zY%(py2)s
{%(py2)s = %(py0)s.target_bot_key_hash
} == %(py7)s
{%(py7)s = %(py4)s(%(py5)s)
}r   rj   r:   r;   r<   rG   rI   assert %(py9)srS   command_preview_sanitizedr   )z%(py0)s not in %(py3)sr:   rO   r`   rG   )r   ri   rj   r   r
   r   r   rp   rq   rn   rr   rs   rt   ru   r   r   ro   r   r   )r   r~   r   r   r   r|   r   r   r   r   r   r   r   s                r   -test_audit_dataclass_field_set_matches_schemar   g  sh   
:,' ("=j\Q_P`aC c344444444:444:444444c444c444444344434444444444sA+ zuuu ""Bl>&BB"&BBBBB"&BBBBBBB3BBB3BBB"BBBBBBlBBBlBBBBBB>BBB>BBB&BBBBBBBB!"#>!??>!?????>!???????>???>???!????????r!   c           	        t        ddt        t        t        t        |        t        ddt        t        t
        d|        | j                  d      }t        |v}|st        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
dz  }t        j                  d      dz   d|iz  }t        t        j                  |            d}t        |v}|st        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
dz  }t        j                  d      dz   d|iz  }t        t        j                  |            d}t         j"                  }d} |||      }| }|sddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        t        j                  |            dx}x}x}}t         j"                  }d} |||      }| }|sddt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }t        t        j                  |            dx}x}x}}y)uT   audit JSONL 전체 텍스트에 raw key / raw session UUID가 1건도 없어야 함.zdev3 indep taskr-   r.   z(dev3 bot task GH_TOKEN=$BOT_GITHUB_TOKENNr#   r   z%(py0)s not in %(py2)srj   textr   u,   raw bot_key가 audit에 노출되면 안 됨r   r<   rk   u1   raw session UUID가 audit에 노출되면 안 됨zghp_[A-Za-z0-9]{20,}zUassert not %(py7)s
{%(py7)s = %(py2)s
{%(py2)s = %(py0)s.search
}(%(py4)s, %(py5)s)
}rer   zghs_[A-Za-z0-9]{20,})r   ri   rj   r   rk   r   r%   rn   ro   rp   rq   rr   rs   rx   rt   ru   r   search)	r    r   r|   r   r   r~   r   @py_assert8r   s	            r   "test_no_raw_secrets_in_audit_jsonlr     so     %'( 9% (D%UUU>UUUUUU>UUU>UUUUUUUUUUUUU'UUUUUUU ,aaa aaaaaa aaa aaaaaaaaaaaaa.aaaaaaayy707y0$77777777777r777r777y7770777777$777$7777777777yy707y0$77777777777r777r777y7770777777$777$7777777777r!   c                 T   dt          dt         dt         } t        |       }t        |v}|st	        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dz  }d	d
|iz  }t        t	        j                  |            d }t        |v}|st	        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dz  }d	d
|iz  }t        t	        j                  |            d }d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }d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  }dd|iz  }t        t	        j                  |            d x}}y )Nz*cokacdir --cron "do thing" --at 2m --chat r    --session r   r   rj   outr   r   r<   rk   z<hash:rK   z%(py1)s in %(py3)sr_   r`   rG   z
(redacted))ri   rj   rk   r   rn   ro   rp   rq   rr   rs   rt   ru   )	rawr   r|   r   r   r   r   r   r   s	            r   5test_sanitize_command_preview_redacts_key_and_sessionr     s   W^$4 5*+	- 
 #3
'C$$$$>$$$$$$>$$$>$$$$$$$$$$$$$$$$ ++++ ++++++ +++ ++++++++++++++++8s?8s8ss<3<3<33r!   c                     t         dd} t        j                  t              5  t	        |        d d d        y # 1 sw Y   y xY w)Nbug)session_id_rawkind)rk   pytestraises
ValueErrorr   payloads    r   .test_ensure_no_raw_secrets_blocks_session_uuidr     s5    !6FG	z	" 'g&' ' 's	   8Ac                 ~    ddi} t        j                  t              5  t        |        d d d        y # 1 sw Y   y xY w)Ncmdz>GH_TOKEN=ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa gh pr merge)r   r   r   r   r   s    r   ,test_ensure_no_raw_secrets_blocks_github_patr     s6    VWG	z	" 'g&' ' 's   3<c                 2	   t        t              } t        t              }g }| |k(  }|}|rd }| |u}|}|rt        |       }d}||k(  }	|	}|sqt        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  }
dd|
iz  }|j                  |       |rwt        j                  d	fd
| f      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }dd|iz  }|j                  |       |rt        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  }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}	}d }t        |      }d }||u }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}d}t        |      }d }||u }|st        j                  d|fd||f      dt        j                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )N   r5   )z%(py2)s == %(py4)sh1h2)r;   r<   z%(py6)sr=   rD   )z%(py8)s is not %(py11)s)r?   py11z%(py13)spy13)z5%(py18)s
{%(py18)s = %(py15)s(%(py16)s)
} == %(py21)sr[   )py15rV   rW   rY   z%(py23)spy23r   zassert %(py26)spy26rb   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)sr   )r:   r;   r<   rI   r   rS    )r   rj   r[   rn   ro   rp   rq   rr   rs   rz   r{   rt   ru   )r   r   r|   r~   r   @py_assert10@py_assert9@py_assert17@py_assert20@py_assert19r   r   @py_format12@py_format14r   @py_format24@py_format25@py_format27r   r}   r   r   s                         r   ,test_hash_bot_key_is_deterministic_and_shortr     sq   	n	%B	n	%B8288$8$83r78b87b=8888288888828882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88$88888887b88888838883888888r888r8887888b88888888888888%<%%%%%%%%%%%%<%%%<%%%%%%%%%%%%%%%%#<#t#t####t######<###<#########t#######r!   c                 N
   dt          dt         dt         t        dfd      } | j                  }d}||u }|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}||u }|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 }| j                  }|}|sd}|}t        |v}|sDdd
t        j                         v st        j                  |       rt        j                  |       nd
t        j                  |      dz  }	|j                  |	       |s+ddt        j                        iz  }
|j                  |
       t        j                   |d      i z  }t        j                  d|fdt        |f      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}x}x}x}}| j"                  }t        |v}|st        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z  }dd|iz  }	t        t        j                  |	            dx}}| j"                  }t        |v}|st        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z  }dd|iz  }	t        t        j                  |	            dx}}y)!uN   cmdline에 cokacdir + --cron + --session 가 모두 있으면 misroute 의심.5/usr/local/bin/cokacdir --cron 'task' --at 2m --chat r   r   4 c                    | rS d S Nr   pidfake_cmdlines    r   <lambda>zNtest_detect_misrouted_session_flags_session_in_cron_dispatch.<locals>.<lambda>      3< D r!   r  cmdline_readerTrb   z:%(py2)s
{%(py2)s = %(py0)s.suspected_misroute
} is %(py5)sreportrF   rH   rI   Nz8%(py2)s
{%(py2)s = %(py0)s.has_session_flag
} is %(py5)sr   z0%(py6)s
{%(py6)s = %(py4)s.session_id_redacted
})r<   r=   rR   rS   rX   r   )z%(py0)s not in (%(py12)s)rk   )r:   rT   zassert %(py14)srU   )zE%(py0)s not in %(py4)s
{%(py4)s = %(py2)s.cmdline_preview_sanitized
}r:   r;   r<   rf   r=   rj   )ri   rj   rk   r   suspected_misroutern   ro   rp   rq   rr   rs   rt   ru   has_session_flagsession_id_redactedrz   r{   cmdline_preview_sanitized)r  r|   r   r~   r   r   r}   r   r   r   r   @py_format11@py_format13@py_format15r   r  s                  @r   <test_detect_misrouted_session_flags_session_in_cron_dispatchr    s   $W^,< =*+	- 
 &@F $$,,$,,,,$,,,,,,6,,,6,,,$,,,,,,,,,,""*d*"d****"d******6***6***"***d*******J)C)CJ)CJ)CrJrJ JJJJJJJJJJJJJJ)CJJJJ)CJJJrJJJJJJJJJ JJJJJJ JJJ JJJJJJJJ(.(H(HH (HHHHH (HHHHHHH HHH HHHHHHHHHHHH(HHHHHHHH!'!A!AA>!AAAAA>!AAAAAAA>AAA>AAAAAAAAAAAA!AAAAAAAAr!   c                 b   dt          dt         t        dfd      } | j                  }d}||u }|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}||u }|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 )Nr  r   i c                    | rS d S r  r   r  s    r   r  zKtest_detect_misrouted_session_no_misroute_for_normal_cron.<locals>.<lambda>  r	  r!   r
  Frb   r  r  rF   rH   rI   r  )ri   rj   r   r  rn   ro   rp   rq   rr   rs   rt   ru   r  )r  r|   r   r~   r   r   r  s         @r   9test_detect_misrouted_session_no_misroute_for_normal_cronr    s   $W^,<	>  &@F $$--$----$------6---6---$----------""+e+"e++++"e++++++6+++6+++"+++e+++++++r!   c                 >   t        dd       } | j                  }d}||u }|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}||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}}y )Nic                    | rd S d S r  r   )r  s    r   r  zGtest_detect_misrouted_session_handles_unreadable_proc.<locals>.<lambda>  s    WZt `d r!   r
  Frb   r  r  rF   rH   rI   proc_cmdline_unreadabler5   )z.%(py2)s
{%(py2)s = %(py0)s.reason
} == %(py5)s)r   r  rn   ro   rp   rq   rr   rs   rt   ru   reason)r  r|   r   r~   r   r   s         r   5test_detect_misrouted_session_handles_unreadable_procr    s    %(CdeF$$--$----$------6---6---$----------==555=55555=555555565556555=55555555555r!   c                ~   g dfd}t        dd||       }|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}}|d   }d}||u }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t	        t        j
                  |            d x}x}}g }|k(  }|st        j                  d|fd|f      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}}y )Nc                ,    j                  | |f       y r  )rz   )r  siginvocationss     r   fake_killerzBtest_soft_kill_dry_run_does_not_invoke_killer.<locals>.fake_killer  s    C:&r!   r  T)dry_runkillerr    actionr%  r5   )z%(py1)s == %(py4)sre   rf   r=   signal_sentFrb   rd   )z%(py0)s == %(py3)sr#  r   r`   rG   )r  intr"  r)  returnNone)	r   rn   ro   rs   rt   ru   rp   rq   rr   )r    r$  r8   r   r~   r   r   r   r|   r   r   r#  s              @r   -test_soft_kill_dry_run_does_not_invoke_killerr,    s   K' !kV`aF((y(y((((y((((((y(((((((- )E) E)))) E))) )))E)))))));";";;"r!   c                 ~   t        ddddd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  }d
d|iz  }t        t        j                  |            d x}x}}| j                  }d}||u }|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                  }t               }||k(  }|st        j                  d|fd||f      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t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )N	task-2526F)worktree_diffworktree_untrackedbranch_unpushed_commitsremote_branch_existsopen_pr_for_taskci_run_for_branchaudit_jsonl_evidencesignalsclean_abortr5   z6%(py2)s
{%(py2)s = %(py0)s.classification
} == %(py5)splanrF   rH   rI   Trb   z;%(py2)s
{%(py2)s = %(py0)s.redispatch_required
} is %(py5)s)zT%(py2)s
{%(py2)s = %(py0)s.signals_with_evidence
} == %(py6)s
{%(py6)s = %(py4)s()
}rB   r9   r>   r?   )r   classificationrn   ro   rp   rq   rr   rs   rt   ru   redispatch_requiredsignals_with_evidencerB   )	r:  r|   r   r~   r   r   r}   r   r   s	            r   8test_evidence_based_recover_clean_abort_when_no_evidencer?    s   !""'',$) %!&$)
D /-/-////-//////4///4//////-///////##+t+#t++++#t++++++4+++4+++#+++t+++++++%%00%0000%00000040004000%0000000000000000000r!   c                    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  }d
d|iz  }t        t        j                  |            d x}x}}| j                  }d}||u }|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 )Nr.  T)r/  r5  r6  contaminated_executionr5   r9  r:  rF   rH   rI   rb   r;  r/  rK   )z=%(py1)s in %(py5)s
{%(py5)s = %(py3)s.signals_with_evidence
}rM   )r   r<  rn   ro   rp   rq   rr   rs   rt   ru   r=  r>  )r:  r|   r   r~   r   r   r   r   s           r   =test_evidence_based_recover_contaminated_when_any_signal_truerB  	  ss   !"&ED :"::":::::":::::::4:::4::::::"::::::::##+t+#t++++#t++++++4+++4+++#+++t+++++++8d888?88888?8888?888888d888d88888888888r!   c                    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}}y )
Nr.  r6  no_evidencer5   r9  r:  rF   rH   rI   )
r   r<  rn   ro   rp   rq   rr   rs   rt   ru   )r:  r|   r   r~   r   r   s         r   9test_evidence_based_recover_no_evidence_when_signals_nonerE    s    !+t<D/-/-////-//////4///4//////-///////r!   c                    t        t        t        j                  dt         d      } d}|| v }|st        j                  d|fd|| f      t        j                  |      dt        j                         v st        j                  |       rt        j                  |       nddz  }d	d
|iz  }t        t        j                  |            d 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}}d}|| v}|st        j                  d|fd|| f      t        j                  |      dt        j                         v st        j                  |       rt        j                  |       nddz  }d	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  }d	d
|iz  }t        t        j                  |            d x}}y )Nr   u   /key=<hash:abcd…>)r3   rh   r   rJ   rK   r   noticer_   r`   rG      )<)z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} < %(py6)sr[   r]   u4   회장 짧은 보고 정합 — 200자 미만 유지rC   r?   Criticalr   )z%(py1)s not in %(py3)sCRITICAL)r   r   r   rv   ri   rn   ro   rs   rp   rq   rr   rt   ru   r[   rx   )	rG  r   r   r   r   r}   r   r   r   s	            r   7test_chairman_notice_is_short_and_not_critical_taxonomyrL    s   )'$BB:,&9:F
 *3)V3333)V333)333333V333V3333333v;TT;TTT;TTTTTT3TTT3TTTTTTvTTTvTTT;TTTTTTTTTTTTTT#:V####:V###:######V###V########:V####:V###:######V###V#######r!   c                    t         dz  dz  t         dz  dz  dz  t         dz  dz  dz  t         d	z  d
z  h} | D ]  }|j                  } |       }|st        j                  d|       dz   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}||k(  }|st        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  }dd|iz  }	t        t        j                  |	            dx}x}}y)u.   task-2526 expected_files = 정확히 4 파일.scriptszsafe_cron_dispatch.pytests
regressionz&test_cron_session_safety_guard_2526.pymemoryspecszcron-targeting-spec.mdutilszcron_targeting_audit.pyzexpected_file missing: zC
>assert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}pr  N   r5   rZ   r[   expectedr]   r>   r?   )_WORKTREE_ROOTr$   rn   rx   rp   rq   rr   rs   rt   ru   r[   ro   )
rV  rT  r|   r~   r   r   r}   r   r   r   s
             r   &test_expected_files_exactly_four_existrX  -  sT    	"%<< </2ZZ!G+.FF #<<	H  9xx8xz8z884QC8888888q888q888x888z8888889x=A=A=A33xx=Ar!   )r   r   r*  r   )r    r   r*  list)r    r   )O__doc__
__future__r   builtinsrp   _pytest.assertion.rewrite	assertionrewritern   r(   r   sysdataclassesr   pathlibr   r   __file__resolveparentrW  strpathremoveinsertscripts.safe_cron_dispatchr   r   r   utils.cron_targeting_auditr	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ri   rj   rk   fixturer    r+   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r,  r?  rB  rE  rL  rX  r   r!   r   <module>rm     se  6 #    	 
   
 h'')0077>>~#(("HHOOC'( 3~& ' 
    2 
#>  3 3
_PB*2)@)@*"O&*$)&P.2*0,@48<
''$B&
,6
1$90
$"
r!   