
    1jM                    x   d Z ddlm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	m
Z
 dZdZdZd	Zd
ZdZdZdZdZdZdZdZdZdZdZdZej6                  j9                  ddd      Ze G d d             Z ej>                  d      Z d(dZ!d)dZ"d*dZ#dZ$d+d Z%d+d!Z&dd"d,d#Z'dddd$ddd%	 	 	 	 	 	 	 	 	 	 	 d-d&Z(g d'Z)y).u  dispatch.anu_executor_provenance — task-2753 Option B provenance-path validator.

Layer A / pure validation, side-effect 0.

envelope(ANU artifact) **부재** 인 untrusted executor_result 를 ANU 가 수거하기 전
**provenance hard-fail 검증** 만 수행하는 순수 함수 모듈. side-effect 0:
  - 파일 write 0 (read-only: capability snapshot + result 파일 sha256 read 만).
  - cron register/remove 0, subprocess 0, merge 0, git/gh import 0.
  - owner_proof_pickup_gate(callback fire 보호) 미참조 — 이 모듈은 collector_result
    생성 여부(=수거 진행/quarantine/skip/duplicate) 만 판정한다. fire 는 frozen gate 경유.

★ raw key 0: 실제 ANU/dev key literal 을 **절대 하드코딩하지 않는다**.
  forbidden key literal 은 ``forbidden_key_literals`` 파라미터로 주입받는다.

신뢰 앵커 = ``memory/capabilities/<task_id>.json`` (dispatch 가 생성·봇 변조 불가:
forbidden_paths 자동 등록). 단일 신호 금지 — 14조건 전부 hard-fail(=quarantine).
    )annotationsN)	dataclass)Optionalprovenance_no_dispatch_recordprovenance_task_id_mismatchprovenance_capsule_sha_mismatchprovenance_source_path_invalidschema_failprovenance_terminal_invalidprovenance_completion_invalidpre_activation_epoch	duplicateprovenance_callback_claimprovenance_self_collector_claimprovenance_self_key_claimprovenance_raw_key!provenance_task_id_path_traversal)PASSPASS_WITH_WARNINGSPARTIALEXECUTOR_RESULT_WRITTENmemoryevents	p0b_inboxc                  T    e Zd ZU dZded<   dZded<   dZded<   dZded	<   dZded
<   y)ProvenanceResultud  provenance 검증 결과.

    - ok=True → provenance 통과 → ANU 가 collector_result(adopted_via="provenance") 생성.
    - ok=False & skip=True → stale epoch → skip(quarantine 아님, move 0/wake 0).
    - ok=False & duplicate=True → ledger 중복 → idempotent no-op.
    - ok=False (그 외) → hard-fail = quarantine (reason enum).
    boolok strreasonsource_result_sha256Fskipr   N)	__name__
__module____qualname____doc____annotations__r!   r"   r#   r        7/home/jay/workspace/dispatch/anu_executor_provenance.pyr   r   6   s7     	HFC "#"D$Itr*   r   z^[A-Za-z0-9._+-]+$c                   t        | t              r| syd| v sd| v ryt        j                  | v s"t        j                  rt        j                  | v ryd| v ryt        j
                  j                  |       ryt        j                  |       syy)u   task_id 가 capability path 구성에 안전한지 검증.

    거부: 빈 문자열 / path separator(`/`,`\`,os.sep/altsep) / `..` traversal sequence /
          absolute path / whitelist(`[A-Za-z0-9._+-]`) 밖 문자.
    F/\z..T)	
isinstancer    ossepaltseppathisabs_TASK_ID_SAFE_REmatch)task_ids    r+   _validate_task_id_safer8   K   st     w$
g~	vvRYY299+?w	ww}}W!!'*r*   c                n   t         j                  j                  t         j                  j                  |dd            }t         j                  j                  t         j                  j                  ||  d            }	 t         j                  j	                  ||g      |k7  ry	 |S # t
        $ r Y yw xY w)u  capability path 를 안전하게 resolve. capabilities root 밖이면 None(hard-fail).

    resolve 후 realpath 가 `<root>/memory/capabilities` 하위가 아니면 None 반환
    (whitelist 통과 후에도 symlink 등 잔여 escape 를 막는 defense-in-depth).
    r   capabilitiesz.jsonN)r0   r3   realpathjoin
commonpath
ValueError)r7   root	caps_root	candidates       r+   _safe_capability_pathrB   `   s       dHn!MNI  iG9E9J!KLI77y)45B C
   s    $B( (	B43B4c                   t        |       syt        | |      }|t        j                  j	                  |      sy	 t        |d      5 }t        j                  |      cddd       S # 1 sw Y   yxY w# t        t        f$ r Y yw xY w)u  ``memory/capabilities/<task_id>.json`` 을 읽어 dict 반환. 미존재/unsafe → None.

    dispatch 가 생성하는 신뢰 앵커(봇 변조 불가). read-only — side-effect 0.
    task_id traversal 방어: _safe_capability_path 로 resolve(밖이면 None).
    Nzutf-8)encoding)
r8   rB   r0   r3   existsopenjsonloadOSErrorr>   )r7   r?   r3   fs       r+   _default_capability_readerrK   r   sy     "'* $/D|277>>$/$) 	 Q99Q<	  	  	 Z  s/   A4 	A(	A4 (A1-A4 1A4 4BBi   c                    t        j                         }t        | d      5 t        fdd      D ]  }|j	                  |        	 ddd       |j                         S # 1 sw Y   |j                         S xY w)u  ``path`` 파일을 chunked streaming 으로 sha256 hexdigest 반환.

    전체 read 가 아니라 1 MiB chunk 로 순차 update — 대용량 파일 OOM 방지.
    결과는 전체 read sha256 과 **동일**(bit-identical). read-only — side-effect 0.
    rbc                 .     j                  t              S N)read_HASH_CHUNK_SIZE)rJ   s   r+   <lambda>z"_default_hash_fn.<locals>.<lambda>   s    !&&)9": r*   r*   N)hashlibsha256rF   iterupdate	hexdigest)r3   hchunkrJ   s      @r+   _default_hash_fnrZ      sk     	A	dD	 Q:C@ 	EHHUO	 ;;= ;;=s   &A!!A9c                    	 t         j                  j                  |       S # t        $ r" t         j                  j	                  |       cY S w xY w)uS   경로 정규화 — realpath 시도(symlink 해소), 실패 시 normpath fallback.)r0   r3   r;   rI   normpath)r3   s    r+   
_normalizer]      s@    &ww%% &ww%%&s   ! (AA)r?   c                 
 t        | t              r| j                         syt        |t              r|j                         sy| j                         }|j                         }	 g 
t        |t              rL|j                         r<
j                  t        j
                  j                  |j                                      
j                  t	        j                                d
fd	} ||      }|D ch c]A  }t        j
                  j                  |      s#t        j
                  j                  |      C }} |||      }	t        ||	z        S c c}w # t        $ r Y yw xY w)u  report_path 가 result.json 자기 자신(self-ref)을 가리키는지.

    task-2755+4 abspath 완전 정렬: result_path · report_path · anchor 를 모두
    동일한 absolute-normalized 기준(``os.path.abspath`` + ``os.path.normpath``,
    **symlink 미해소**)으로 후보 집합화한 뒤 교집합 여부로 self-ref 를 판정한다.
    상대경로는 root(제공 시)·cwd·result 디렉토리 anchor 각각으로 절대화하여,
    절대/상대 어떤 조합(abs+abs, rel+rel, abs+rel, rel+abs)이든 동일 파일이면
    self-ref 로 인식된다. realpath/symlink 는 해소하지 않는다(abspath 기준 통일).

    불변 조건:
      - report_path/result_path 가 None/빈 str/공백 → False (조건5 REASON_SCHEMA_FAIL 유지).
      - 자기 자신이 아닌 다른 report_path → False.
      - path traversal / root 밖 혼동 → 절대화 후 경로 불일치로 False(fail-safe).
      - 예외 발생 → False(fail-closed).
    Fc                   t         j                  j                  |       r t         j                  j                  |       hS t	               }t              t        |      z   D ]k  }|j                  t         j                  j                  t         j                  j                  t         j                  j                  ||                          m |S rO   )	r0   r3   r4   r\   setlistaddabspathr<   )r3   extra_anchorsoutabase_anchorss       r+   _candidatesz)report_path_self_ref.<locals>._candidates   s    ww}}T"((.//%C,'$}*== R((a9N)OPQRJr*   )r)   )r/   r    stripappendr0   r3   rc   getcwddirnamer   	Exception)report_pathresult_pathr?   rpresrh   	res_candscres_dirs	rep_candsrg   s             @r+   report_path_self_refrv      s     {C([->->-@{C([->->-@				B



CdC TZZ\

 =>BIIK(	  $	09P1RWW__Q=OBGGOOA&PPH-	I	)** Q  s+   %BE 8$E!E>E E 	E('E(r)   )capability_readeractivation_epochledger_readerforbidden_key_literalsstat_fnhash_fnc                  |xs fd}	|xs t         }|xs t        j                  }t        | t              st        dt              S | j                  d      }
t        |
t              r|
j                         st        dt              S |
j                         }
t        |
      st        dt              S 	  |	|
      }t        |t              st        dt              S | j                  d      |j                  d      k7  rt        dt              S | j                  d      }|j                  d      }t        |t              r|st        dt              S ||k7  rt        dt              S t!        t        j"                  j%                  t&        |
 d            }t!        |      }||k7  rt        dt(              S | j                  d	      }t        |t              r|j                         st        dt              S | j                  d
      t*        vrt        dt,              S | j                  d      t.        k7  rt        dt0              S 	  ||      }t        |      }|?	  ||      }t5        |j6                        }|t5        |      k  rt        ddt<        |      S |(	 t?         ||
|            }|rt        ddt@        |      S t?        | j                  d            s4t?        | j                  d            st?        | j                  d            rt        dtB        |      S t?        | j                  d            rt        dtD        |      S t?        | j                  d            rt        dtF        |      S |rC	 tI        jJ                  | d      }|D ]&  }|st        |      |v st        dtN        |      c S  t        d|      S # t        $ r d}Y ,w xY w# t2        $ r t        dt(              cY S w xY w# t2        t8        t:        f$ r t        ddt<        |      cY S w xY w# t        $ r d}Y w xY w# tL        t:        f$ r t        |       }Y w xY w)u   envelope 부재 executor_result 의 provenance 를 14조건 hard-fail 검증.

    검사 순서: 1→2→3→4→5→6→7→8(sha계산)→9→10→11→12→13→14.
    전부 통과 → ProvenanceResult(ok=True, source_result_sha256=<sha>).
    c                    t        |       S rO   )rK   )tidr?   s    r+   rR   z.validate_executor_provenance.<locals>.<lambda>   s    3McSW3X r*   F)r   r!   r7   Ncapsule_sha256source_sha256z.result.jsonrn   terminal_statuscompletion_signalT)r   r#   r!   r"   )r   r   r!   r"   callback_schedule_createdschedule_created_by_executorcallback_fired_by_executor)r   r!   r"   self_collectorowner_key_proof_present)ensure_ascii)r   r"   )(rZ   r0   statr/   dictr   REASON_SCHEMA_FAILgetr    ri   r8   REASON_TASK_ID_PATH_TRAVERSALrm   REASON_NO_DISPATCH_RECORDREASON_TASK_ID_MISMATCHREASON_CAPSULE_SHA_MISMATCHr]   r3   r<   	INBOX_RELREASON_SOURCE_PATH_INVALIDVALID_TERMINAL_STATUSREASON_TERMINAL_INVALIDEXECUTOR_COMPLETION_SIGNALREASON_COMPLETION_INVALIDrI   floatst_mtimeAttributeErrorr>   REASON_PRE_ACTIVATION_EPOCHr   REASON_DUPLICATEREASON_CALLBACK_CLAIMREASON_SELF_COLLECTOR_CLAIMREASON_SELF_KEY_CLAIMrG   dumps	TypeErrorREASON_RAW_KEY)resultro   r?   rw   rx   ry   rz   r{   r|   
cap_readerr7   snapshotcapsule_shasnap_shaexpectedactualrn   shastmtimedupblobliterals     `                    r+   validate_executor_provenancer      s,   " #Y'XJ))G G fd#51CDDjj#Gw$51CDDmmoG "'*51NOOg& h%51JKK zz)Y 7751HII **-.K||O,H{C([51LMMh51LMM "'',,tY7)<8PQRH$F51KLL **]+K{C([->->-@51CDD zz#$,AA51HII zz%&*DD51JKKMk" c(C #		%B"++&E 5)**#t2%(   	}Wc23C #D'%(  	VZZ345

9:;

7892
 	

 FJJ'()8s
 	

 FJJ0122
 	

 	::f59D . 	G3w<4/'^# 	 t#>>q  `  M51KLLM 4 	#t2%( 	$  	C	F :& 	v;D	sZ   9O O1 -P .P> Q O.-O.1PP'P;:P;>QQQ-,Q-)r   r   rv   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r7   r    returnr   )r7   r    r?   r    r   Optional[str])r7   r    r?   r    r   zOptional[dict])r3   r    r   r    )r?   r   r   r   )r   objectro   r    r?   r    rx   zOptional[float]rz   tupler   r   )*r'   
__future__r   rS   rG   r0   redataclassesr   typingr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r3   r<   r   r   compiler5   r8   rB   rK   rQ   rZ   r]   rv   r   __all__r)   r*   r+   <module>r      sX  " #   	 	 !  < 7 ? = " 7 ; 4  3 ? 3 % C  B 6  GGLL8[9	   " 2::34 *$&  
& MQ ,j (,$&^?^?^? 	^? &^? "^? ^?Br*   