
    +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mZ ddlZ ee      j!                         j"                  d   Z ee      ej(                  vr"ej(                  j+                  d ee             edz  dz  dz  Z ee      ej(                  vr"ej(                  j+                  d ee             ddlZ ej2                  d	
      dd       ZddZddZddZddZddZddZ ddZ!ddZ"ddZ#ddZ$ddZ%ddZ&ddZ'ddZ(y)u  task-2729+5 P0-b audit decision check — 회귀 테스트.

대상 스크립트: scripts/harness/v36/anu_pickup_p0b_audit_decision_check.py
공개 함수: make_isolated_root, write_result_json, fake_pickup_factory,
           fake_verify_factory, fixed_clock, run_checks, snapshot_canonical,
           assert_canonical_untouched, main.

절대 제약:
  - ANU key literal(16hex/c119085 전체 키) 절대 작성 금지.
  - pickup_once 실 발사 0 (스크립트가 mock 처리).
  - canonical(/home/jay/workspace) write 0.
    )annotationsN)Path   scriptsharnessv36module)scopec                 *    t        j                         S )u7   run_checks() 를 모듈 전체에서 한 번만 실행.)chk
run_checks     P/home/jay/workspace/tests/regression/test_anu_pickup_p0b_audit_decision_check.pysummaryr   +   s     >>r   c                l   | d   }d}||u }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d| d   D cg c]
  }|d   r	| c}       d	z   d
|iz  }t	        t        j
                  |            dx}x}}yc c}w )u-   run_checks() → summary["all_pass"] is True.all_passTisz%(py1)s is %(py4)spy1py4u   all_pass=False. 실패 항목: checkspassed
>assert %(py6)spy6N
@pytest_ar_call_reprcompare	_saferepr_format_assertmsgAssertionError_format_explanation)r   @py_assert0@py_assert3@py_assert2@py_format5c@py_format7s          r   test_run_checks_all_passr+   4   s    : $ $&  $        #'    *x(<!(A<
=	?     <s   ,
B1
7B1
c                   | 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)	u!   canonical root 는 변경 없음.canonical_untouchedTr   r   r   assert %(py6)sr   Nr   r    r!   r#   r$   r   r%   r&   r'   r(   r*   s         r   test_canonical_untouchedr1   ?   sU    ()1T1)T1111)T111)111T1111111r   c                   | 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}}y)	u   ANU raw key 노출 0건.raw_key_exposurer   ==z%(py1)s == %(py4)sr   r.   r   Nr/   r0   s         r   test_raw_key_exposure_zeror7   G   sU    %&+!+&!++++&!+++&+++!+++++++r   c                   | d   }g }||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)u   이슈 발견 0건.findingsr4   r6   r   r.   r   Nr/   r0   s         r   test_no_findingsr:   O   sT    :$"$"$$$$"$$$$$$"$$$$$$$r   c                (   | d   }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  dt        |       d      d	z   d
|iz  }t        t        j                  |            dx}x}}|D cg c]
  }|d   r	| }}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c c}w )u'   DC1~DC11 모두 passed=True, 총 11개.r      r4   z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenpy0r   py3r   u   check 개수=z (expected 11)
>assert %(py8)spy8Nr   z%(py0)s == %(py3)sfailedr@   rA   u   실패 항목: 
>assert %(py5)spy5
r>   r   r    @py_builtinslocals_should_repr_global_namer!   r"   r#   r$   )r   r   r'   @py_assert5@py_assert4r*   @py_format9r)   rE   @py_assert1@py_format4@py_format6s               r   test_each_decision_check_passedrS   W   s5   XFv;I"I;"III;"IIIIII3III3IIIIIIvIIIvIII;III"IIIc&k].IIIIIIII3Aq{a3F336R<3336R33333363336333R333?6(3333333 4s   >
H	Hc                   | d   dfd} |d      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d	|d    d
      dz   d|iz  }t	        t        j
                  |            dx}x}} |d      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d    d
      dz   d|iz  }t	        t        j
                  |            dx}x}}g d}	|	D ]  }
 ||
      }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d    d|d    d      dz   d|iz  }t	        t        j
                  |            dx}x}} y)u>   DC3(wake)=1, DC9(dedupe)=1, 나머지 no-op/quarantine/skip=0.r   c                   D cg c]  }| |d   v s| }}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d|  d	|       d
z   d|iz  }t        t        j                  |            d x}x}}|d   S c c}w )Nname   r4   r=   r>   matchedr?   'u   ' 매칭 check=rB   rC   r   rI   )	substrr)   rX   r'   rM   rN   r*   rO   r   s	           r   get_by_substrz7test_wake_scenarios_pickup_calls.<locals>.get_by_substrf   s    $<!F)(;1<<7|FqF|q FFF|qFFFFFFsFFFsFFFFFF7FFF7FFF|FFFqFFFAfX_WI"FFFFFFFFqz =s
   EEauthoritative_wakepickup_callsrW   r4   r6   r   zDC3 pickup_calls=z (expected 1)r   r   Nduplicate_preventionzDC9 pickup_calls=)	disabled_noopenabled_nontargetterminal_marker_skipdedupe_skipowner_proof_failreadiness_defernull_byte_quarantinesealed_key_missingterminal_skipr   rY   rV   z' pickup_calls=z (expected 0))rZ   strreturndictr   )r   r[   dc3r%   r&   r'   r(   r*   dc9noop_substringsrZ   r)   r   s               @r    test_wake_scenarios_pickup_callsrn   b   s   XF ,
-C~ ! !#  !        #$    C/0>     .
/C~ ! !#  !        #$    C/0>    

O " 
&!  	
A 	
 A% 	
 	
 A 	
 	
 		 ! 	
 	
 		 %& 	
 	
  &	{/!N*;)<MJ	
 	
 	
 	
 	
 	

r   c                j   | d   }t        d |D              }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d         d	z   d
|iz  }t        t        j                  |            dx}x}}y)zDC1: actual == 'NOOP_DISABLED'.r   c              3  0   K   | ]  }d |d   v s|  yw)r_   rV   Nr   .0r)   s     r   	<genexpr>z-test_disabled_noop_verdict.<locals>.<genexpr>   s     AQOqy$@qA   actualNOOP_DISABLEDr4   r6   r   zDC1 actual=r   r   Nnextr   r    r!   r"   r#   r$   )r   r   dc1r%   r&   r'   r(   r*   s           r   test_disabled_noop_verdictrz      s    XF
A&A
ACx= O =O+  =O        ,    c(m&'     r   c                j   | d   }t        d |D              }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d         d	z   d
|iz  }t        t        j                  |            dx}x}}y)u7   DC4: terminal marker no-op → actual == 'PICKUP_SKIP'.r   c              3  0   K   | ]  }d |d   v s|  yw)ra   rV   Nr   rq   s     r   rs   z,test_terminal_marker_noop.<locals>.<genexpr>   s     HQ$:ai$GqHrt   ru   PICKUP_SKIPr4   r6   r   zDC4 actual=r   r   Nrw   )r   r   dc4r%   r&   r'   r(   r*   s           r   test_terminal_marker_noopr      s    XF
H&H
HCx= M =M)  =M        *    c(m&'     r   c                j   | d   }t        d |D              }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d         d	z   d
|iz  }t        t        j                  |            dx}x}}y)u/   DC5: ledger dedupe → actual == 'PICKUP_SKIP'.r   c              3  0   K   | ]  }d |d   v s|  yw)rb   rV   Nr   rq   s     r   rs   z#test_dedupe_noop.<locals>.<genexpr>   s     ?QMQvY$>q?rt   ru   r}   r4   r6   r   zDC5 actual=r   r   Nrw   )r   r   dc5r%   r&   r'   r(   r*   s           r   test_dedupe_noopr      s    XF
?&?
?Cx= M =M)  =M        *    c(m&'     r   c                j   | d   }t        d |D              }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d         d	z   d
|iz  }t        t        j                  |            dx}x}}y)u<   DC6: 비-AUTHORITATIVE verify_fn → actual == 'QUARANTINE'.r   c              3  0   K   | ]  }d |d   v s|  yw)rc   rV   Nr   rq   s     r   rs   z3test_owner_proof_fail_quarantine.<locals>.<genexpr>   s     DQ$6!F)$CqDrt   ru   
QUARANTINEr4   r6   r   zDC6 actual=r   r   Nrw   )r   r   dc6r%   r&   r'   r(   r*   s           r    test_owner_proof_fail_quarantiner      s    XF
D&D
DCx= L =L(  =L        )    c(m&'     r   c                   | d   }t        d |D              }|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d         d	z   d
|iz  }t        t        j                  |            dx}x}}|d   }d}||k(  }|st        j                  d|fd||f      t        j                  |      t        j                  |      dz  }t        j                  d|d    d      d	z   d
|iz  }t        t        j                  |            dx}x}}y)uH   DC10: sealed_key_loader=None → actual == 'SEALED_KEY_MISSING', wake 0.r   c              3  0   K   | ]  }d |d   v s|  yw)rf   rV   Nr   rq   s     r   rs   z5test_sealed_key_missing_failclosed.<locals>.<genexpr>   s     Ga%9QvY%FGrt   ru   SEALED_KEY_MISSINGr4   r6   r   zDC10 actual=r   r   Nr]   r   zDC10 pickup_calls=z (expected 0, fail-closed)rw   )r   r   dc10r%   r&   r'   r(   r*   s           r   "test_sealed_key_missing_failclosedr      sI   XFG6GGD> 1 >11  >1        2    tH~()      1 1$  1         $%    T.122LM     r   c                    d} t        j                         }	 |j                  } ||       }| }|st        j                  d|       dz   dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }t        t        j                  |            dx}x}}ddl}|j                  }|j                  } ||      }|st        j                  d	|       d
z   dt        j                         v st        j                  |      rt        j                  |      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}}t        j                  |d       y# t        j                  |d       w xY w)uF   make_isolated_root() 반환 경로가 canonical root 아래가 아님.z/home/jay/workspaceu8   make_isolated_root() 가 canonical 경로를 반환함: zR
>assert not %(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py3)s)
}rootCANONICAL_PREFIX)r@   py2rA   rH   Nr   u   temp dir 미생성: zc
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.path
}.isdir
}(%(py5)s)
}os)r@   r   r   rH   py7T)ignore_errors)r   make_isolated_root
startswithr   r"   rJ   rK   rL   r!   r#   r$   r   pathisdirshutilrmtree)	r   r   rP   rN   @py_assert6r*   r   r&   @py_format8s	            r   %test_make_isolated_root_not_canonicalr      s   ,!!#D0?? 	
?#34 	
44 	
4 	
  GtfM	
 	
	6	
 	
   	
 	
 		  	
 	
 		 # 	
 	
	6	
 	
  $4 	
 	
 		 $4 	
 	
 		 5 	
 	
 	
 	
 	
 	wwAw}}A}T"A"AA&:4&$AAAAAAArAAArAAAwAAA}AAAAAATAAATAAA"AAAAAAd$/d$/s   H-I I6c                   t        j                  dg      }| j                         }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d|j                  d	d
        dz   d|iz  }t        t        j                  |            d	x}}t        j                  |j                        }t        |t               }|s!t        j                  d      dz   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	}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   }
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	)u1   main(['--json']) == 0, stdout 이 유효한 JSON.z--jsonr   r4   rD   	exit_coderF   zmain exit_code=z (expected 0). stdout=N   rG   rH   u   stdout 이 dict JSON 이 아님z7
>assert %(py4)s
{%(py4)s = %(py0)s(%(py1)s, %(py2)s)
}
isinstanceparsedrj   )r@   r   r   r   r   )in)z%(py1)s in %(py3)s)r   rA   zassert %(py5)sTr   r   r   r.   r   )r   main
readouterrr   r    rJ   rK   rL   r!   r"   outr#   r$   jsonloadsr   rj   )capsysr   capturedr'   rP   rQ   rR   r   r&   r(   r%   r*   s               r   test_main_exit_zeror      s$   ($I  "H 9>  9                  )$:8<<;M:NO     ZZ%Ffd#F#FF%FFFFFFF:FFF:FFFFFFfFFFfFFFFFFdFFFdFFF#FFFFFF:::*%%%%%%%%%%%%%%%%%%%r   c                   t        j                  |       }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
}y
)uE   summary JSON 에 'c119085' 부분문자열 없음 (raw key 노출 0).c119085)not in)z%(py0)s not in %(py2)s
key_prefixdump)r@   r   u-   summary JSON 에 ANU key prefix 가 노출됨z
>assert %(py4)sr   N)r   dumpsr   r    rJ   rK   rL   r!   r"   r#   r$   )r   r   r   rP   @py_format3r(   s         r   test_no_real_anu_key_in_summaryr      s    ::gD8JT!  :T                "    "    	8    r   )ri   rj   )r   rj   ri   None)ri   r   )r   zpytest.CaptureFixtureri   r   ))__doc__
__future__r   builtinsrJ   _pytest.assertion.rewrite	assertionrewriter   r   r   syspathlibr   pytest__file__resolveparents_ROOTrh   r   insertHARNESS_DIR#anu_pickup_p0b_audit_decision_checkr   fixturer   r+   r1   r7   r:   rS   rn   rz   r   r   r   r   r   r   r   r   r   r   <module>r      s   #     
   	X ((+u:SXXHHOOAs5z" i)+e3{388#HHOOAs;'(
 2 h  2,%4$
T
 0$&"r   