
    Mj(                       d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlZddlZddlmZ ddlZ ee      j%                         j&                  d   Z ed      Z ed      ZdddZej0                  dd	       Zdd
ZddZddZddZej<                  j?                  dg d      dd       Z ddZ!ddZ"ddZ#ddZ$y)ui  Axis 3 restricted canary smoke test — SP1..SP7.

chair_authorization_id = CHAIR-AUTH-AXIS-3-CANARY-20260524-JJONGS-RESTRICTED-001

Each SP simulates a single PreToolUse hook invocation by piping a synthetic
event payload into the live hook script. Asserts on exit code + audit log.
PYTHONPATH-agnostic: classifier is imported via explicit sys.path bootstrap.
    )annotationsN)Path   z</home/jay/.claude/hooks/pre_tool_use_runtime_guard_canary.pyz/home/jay/workspacec                (   t         j                  j                         }d|d<   |t        |      |d<   |r|j	                  |       t        j                  t        j                  t        t              gt        j                  |       dd|d      }|S )NtrueANU_CANARY_AXIS_3ANU_WORKSPACE_ROOTT
   inputcapture_outputtextenvtimeout)osenvironcopystrupdate
subprocessrunsys
executable	HOOK_PATHjsondumps)payload	extra_envworkspace_rootr   procs        F/home/jay/workspace/tests/integration/test_axis_3_restricted_canary.py	_run_hookr"      s    
**//
C%C!$'$7 !

9>>	Y(jj!D K    c                   | dz  dz  j                  dd       t        dz  }| dz  }|j                         sL|j                  dd       dD ]  }t        j                  ||z  ||z           |dz  j                  dd	
       | S )zCreate an isolated workspace root with a memory/system subtree so the
    hook writes audit logs into the sandbox instead of the live tree.
    memorysystemT)parentsexist_okutils)zruntime_guard_classifier.pyzruntime_guard_policy_map.pyz__init__.py utf-8encoding)mkdir	REPO_ROOTexistsshutilcopy2
write_text)tmp_path	utils_src	utils_dstfnames       r!   isolated_audit_dirr8   .   s    
 8#**4$*GG#I7"It4S 	?ELLU*I,=>	? 
]	"..rG.DOr#   c                   | j                         sg S g }| j                  d      j                         D ]:  }|j                         }|s	 |j	                  t        j                  |             < |S # t
        j                  $ r Y Tw xY w)Nr+   r,   )r0   	read_text
splitlinesstripappendr   loadsJSONDecodeError)pathoutlines      r!   _read_jsonlrC   @   s    ;;=	
C0;;= zz|	JJtzz$'( J ## 		s   $A44B
	B
c                   ddddid}t        ||       }|j                  }d}||k(  }|st        j                  d|fd	||f      d
t	        j
                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }t        j                  d|j                   d|j                         dz   d|iz  }t        t        j                  |            dx}x}}t        | dz        }d |D        }t        |      }|st        j                  d|       dz   dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)u>   Plain Read tool — must allow (exit 0) and record AUDIT_ONLY.dev5-canary-session-testRead	file_pathz/home/jay/workspace/README.md
session_id	tool_name
tool_inputr   r   ==z2%(py2)s
{%(py2)s = %(py0)s.returncode
} == %(py5)sr    py0py2py5zSP1 expected exit 0, got : 
>assert %(py7)spy7N1memory/system/.axis_3_canary_decision_audit.jsonlc              3  D   K   | ]  }|j                  d       dk(    yw)decision
AUDIT_ONLYNget.0rs     r!   	<genexpr>z'test_SP1_normal_noop.<locals>.<genexpr>\   s     >QquuZ L0>    z%SP1 decision log missing AUDIT_ONLY: .
>assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyrQ   rR   py4)r"   
returncode
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_saferepr_format_assertmsgstderrAssertionError_format_explanationrC   rc   
r8   r   r    @py_assert1@py_assert4@py_assert3@py_format6@py_format8log@py_format5s
             r!   test_SP1_normal_noopry   R   s@    1"$CDG
 W-?@D??]a]?a]]]?a]]]]]]4]]]4]]]?]]]a]]]#<T__<MRPTP[P[}!]]]]]]]]
(+^^
_C>#>m3>>m>mmBghkgl@mmmmmmm3mmm3mmm>mmm>mmmmmmr#   c                   ddddddd}t        ||       }|j                  }d	}||k(  }|st        j                  d
|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                         dz   d|iz  }t        t        j                  |            dx}x}}t        | dz        }d |D        }t        |      }|st        j                  d|       dz   dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)uD   Edit on dispatch.py forbidden_path — must allow (WARN, not BLOCK).rE   Editz/home/jay/workspace/dispatch.pyxy)rG   
old_string
new_stringrH   rL   r   rM   rO   r    rP   z)SP2 expected allow (forbidden=WARN), got rU   rV   NrW   c              3  p   K   | ].  }|j                  d       dk(  xr |j                  d      dk(   0 yw)rY   WARNcategoryforbidden_pathNr[   r]   s     r!   r`   z/test_SP2_forbidden_path_warn.<locals>.<genexpr>p   s6     bYZquuZ F*TquuZ/@DT/TTb   46z)SP2 expected WARN forbidden_path in log: rb   rc   rd   r"   rf   rg   rh   ri   rj   rk   rl   rm   ro   rp   rC   rc   rq   s
             r!   test_SP2_forbidden_path_warnr   b   sp    1:
G W-?@D??^a^?a^^^?a^^^^^^4^^^4^^^?^^^a^^^#LT__L]!^^^^^^^^
(+^^
_Cb^ab 3bb b   4C59             c    c     r#   c                   dddddd}t        ||       }|j                  }d}||k(  }|st        j                  d	|fd
||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                         dz   d|iz  }t        t        j                  |            dx}x}}t        | dz        }d |D        }t        |      }|st        j                  d|       dz   dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)u1   Write containing AWS key pattern — WARN, allow.rE   Writez/tmp/nope.txtz&leaked AKIAABCDEFGHIJKLMNOP credentialrG   contentrH   rL   r   rM   rO   r    rP   z*SP3 expected allow (credential=WARN), got rU   rV   NrW   c              3  p   K   | ].  }|j                  d       dk(  xr |j                  d      dk(   0 yw)rY   r   r   credential_patternNr[   r]   s     r!   r`   z3test_SP3_credential_pattern_warn.<locals>.<genexpr>   s6     f]^quuZ F*XquuZ/@DX/XXfr   z-SP3 expected WARN credential_pattern in log: rb   rc   rd   r   rq   s
             r!    test_SP3_credential_pattern_warnr   x   sm    1(?
G W-?@D??_a_?a___?a______4___4___?___a___#MdooM^!________
(+^^
_Cfbef 3ff f   8u=             g    g     r#   zcommand,expected_rule))rm -rf /zdestructive.rm_rf_root)zgit push --force origin mainzdestructive.git_push_force_main)z"git reset --hard some_other_branchz'destructive.git_reset_hard_other_branch)zgit branch -D mainz"destructive.git_branch_delete_main)zcokacdir --cron-remove abc123z destructive.cokacdir_cron_removec                   ddd|id}t        ||       }|j                  }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |      rt        j                  |      nd	t        j                  |      t        j                  |      d
z  }t        j                  d| d|j                   d|j                         dz   d|iz  }	t        t        j                  |	            dx}x}}|j                  }
||
v }|st        j                  d|fd||
f      dt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  |
      rt        j                  |
      nddz  }t        j                  d| d| d|
       dz   d|iz  }t        t        j                  |            d}y)uB   Each destructive command — BLOCK (exit 2) with matching rule id.rE   BashcommandrH   rL   r   rM   rO   r    rP   zSP4 [z] expected exit 2 (BLOCK), got rT   rU   rV   N)in)z%(py0)s in %(py2)sexpected_rulebody)rQ   rR   z] expected rule z in stdout: z
>assert %(py4)sre   )r"   rf   rg   rh   ri   rj   rk   rl   rm   stdoutro   rp   )r8   r   r   r   r    rr   rs   rt   ru   rv   r   @py_format3rx   s                r!   test_SP4_destructive_blockr      sX    1 '*G
 W-?@D??qaq?aqqq?aqqqqqq4qqq4qqq?qqqaqqq5	1PQUQ`Q`Paacdhdodocp!qqqqqqqq;;DD ddd=Ddddddd=ddd=ddddddDdddDddddE'2B=/Q]^b]c"dddddddr#   c           	     b   dddddddddddd	diddd	d
idg}|D ]  }ddi|}t        ||       }|j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|d    d|d    d|j                         dz   d|iz  }	t        t        j                  |	            dx}x}} y)zBCallback ledger append + callback inbox write must NOT be blocked.r   z8/home/jay/workspace/memory/system/.callback_ledger.jsonlz
{"foo":1}
r   )rJ   rK   z6/home/jay/workspace/memory/.callback_inbox/sample.jsonz{}rF   rG   z2/home/jay/workspace/utils/callback_registration.pyrI   rE   rL   r   rM   rO   r    rP   z SP5 Axis 1/2 interference: tool=rJ   z input=rK   z exit=rU   rV   N)r"   rf   rg   rh   ri   rj   rk   rl   rm   ro   rp   )
r8   casescr   r    rr   rs   rt   ru   rv   s
             r!   !test_SP5_axis_1_2_no_interferencer      sp    !W(	
 !U	
  W	
  Q	
/E<  
!;AqA1CD 	
! 	
!# 	
 	
! 	
 	
	6	
 	
   	
 	
 		  	
 	
 		  	
 	
 		 #$ 	
 	
  /q~.>gaoEVV\]a]l]l\mn	
 	
 	
 	
 	
 	

r#   c                   ddddid}t        |ddi|       }|j                  }d	}||k(  }|st        j                  d
|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                   d|j                         dz   d|iz  }t        t        j                  |            dx}x}}t        | dz        }d |D        }t        |      }|st        j                  d|       dz   dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)uF   ANU_DISPATCH_RUNNING=1 → AUDIT_ONLY exclusion regardless of payload.zdispatch-sessionr   r   r   rH   ANU_DISPATCH_RUNNING1r   r   r   rM   rO   r    rP   z$SP6 dispatch must pass through, got rT   rU   rV   NrW   c              3  D   K   | ]  }|j                  d       dk(    yw)rule_idzsession.dispatch_excludedNr[   r]   s     r!   r`   z+test_SP6_dispatch_bypass.<locals>.<genexpr>   s     L1quuY#>>Lra   z/SP6 expected session.dispatch_excluded in log: rb   rc   rd   r"   rf   rg   rh   ri   rj   rk   rl   rm   r   ro   rp   rC   rc   rq   s
             r!   test_SP6_dispatch_bypassr      s    ) *-	G )3/)D
 ??hah?ahhh?ahhhhhh4hhh4hhh?hhhahhh#GGXXZ[_[f[fZg!hhhhhhhh
(+^^
_CLL 3LL L   :#?             M    M     r#   c                   ddddid}t        |ddi|       }|j                  }d	}||k(  }|st        j                  d
|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|j                   d|j                         dz   d|iz  }t        t        j                  |            dx}x}}t        | dz        }d |D        }t        |      }|st        j                  d|       dz   dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }	t        t        j                  |	            dx}}y)uF   Forced crash via ANU_AXIS_3_CANARY_FORCE_CRASH=1 — must still allow.rE   r   r   r   rH   ANU_AXIS_3_CANARY_FORCE_CRASHr   r   r   rM   rO   r    rP   zSP7 fail-safe broke: exit rT   rU   rV   Nz3memory/system/.axis_3_canary_hook_crash_audit.jsonlc              3  D   K   | ]  }|j                  d       dk(    yw)stageforced_simulationNr[   r]   s     r!   r`   z0test_SP7_hook_crash_fail_safe.<locals>.<genexpr>   s     HquuW~!44Hra   z*SP7 expected forced_simulation crash log: rb   rc   rd   r   )
r8   r   r    rr   rs   rt   ru   rv   	crash_logrx   s
             r!   test_SP7_hook_crash_fail_safer      s    1 *-G
 2C8)D
 ??^a^?a^^^?a^^^^^^4^^^4^^^?^^^a^^^#=doo=NbQUQ\Q\P]!^^^^^^^^.1ffgIHiH 3HH H   5YK@             I    I     r#   c                   t         j                  j                         }|j                  dd       t	        |       |d<   ddddid}t        j                  t        j                  t	        t              gt        j                  |      d	d	|d
      }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                          v st        j"                  |      rt        j$                  |      ndt        j$                  |      t        j$                  |      dz  }t        j&                  d|j                         dz   d|iz  }t)        t        j*                  |            dx}x}}t-        | dz        }	g }
|	|
k(  }|st        j                  d|fd|	|
f      dt        j                          v st        j"                  |	      rt        j$                  |	      ndt        j$                  |
      dz  }t        j&                  d|	       dz   d|iz  }t)        t        j*                  |            dx}}
y)zFWithout ANU_CANARY_AXIS_3=true, hook must noop and NOT write any logs.r   Nr	   znon-canary-sessionr   r   r   rH   Tr
   r   r   rM   rO   r    rP   z non-canary must noop allow, got rU   rV   rW   )z%(py0)s == %(py3)srw   )rQ   py3z(non-canary must not write decision log: z
>assert %(py5)srS   )r   r   r   popr   r   r   r   r   r   r   r   rf   rg   rh   ri   rj   rk   rl   rm   ro   rp   rC   )r8   r   r   r    rr   rs   rt   ru   rv   rw   @py_assert2@py_format4s               r!   test_canary_env_flag_off_noopr      s   
**//
CGG& #$6 7C* *-G
 >>	Y(jj!D ??UaU?aUUU?aUUUUUU4UUU4UUU?UUUaUUU#CDOOCT!UUUUUUUU
(+^^
_CF3"9FFF3"FFFFFF3FFF3FFF"FFF@FFFFFFFr#   )NN)r   dictr   zdict | Noner   zPath | Nonereturnzsubprocess.CompletedProcess)r4   r   r   r   )r@   r   r   z
list[dict])r8   r   )r8   r   r   r   r   r   )%__doc__
__future__r   builtinsri   _pytest.assertion.rewrite	assertionrewriterg   r   r   r1   r   r   pathlibr   pytest__file__resolver'   r/   r   WORKSPACE_LIVEr"   fixturer8   rC   ry   r   r   markparametrizer   r   r   r   r    r#   r!   <module>r      s    #    	   
  N""$,,Q/	OP	+,
$  "$
n ,* 	
e	
e %
V.,Gr#   