
     j&*                    4   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mZ ddl	m
Z
 ddlmZ  eh d      Z e
d      Zd	Zdd
ZddZdddZddZdd	 	 	 	 	 	 	 	 	 ddZdd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZy)uO  utils/review_thread_guard.py — Gemini review thread 임의 resolve 차단 + audit.

task-2472 구현 1: resolveReviewThread 호출 경로 통제.
medium/high/critical severity thread는 chairman approval evidence 없으면 resolve 불가.
fail-closed: 거부 시 GraphQL mutation 절대 호출 안 함. audit 누락 시도 시 fail.
    )annotationsN)datetimetimezone)Path)Optional>   highmediumcriticalz9memory/orchestration-audit/review-thread-resolution.jsonlz
mutation ResolveThread($threadId: ID!) {
  resolveReviewThread(input: {threadId: $threadId}) {
    thread {
      id
      isResolved
    }
  }
}
c                 f    t        j                  t        j                        j	                  d      S )zISO 8601 UTC.z%Y-%m-%dT%H:%M:%SZ)r   nowr   utcstrftime     0/home/jay/workspace/utils/review_thread_guard.py_now_isor   ,   s!    <<%../CDDr   c                    t        j                  | dd      }t        j                  |j	                  d            j                         S )u2   sha256(json.dumps(record, sort_keys=True)) 반환.TF)	sort_keysensure_asciiutf-8)jsondumpshashlibsha256encode	hexdigest)record
serializeds     r   _evidence_hash_strr   1   s7    FdGJ>>*++G45??AAr   c                \    | xs) t        t        j                  j                  dd            S )NWORKSPACE_ROOTz/home/jay/workspace)r   osenvironget	workspaces    r   _workspace_rootr'   7   s#    URZZ^^,<>STUUr   c                P   t        | t              syh d}|t        | j                               z
  }|rddt	        |       fS | j                  dd      j                         sy| j                  dd      j                         sy	| j                  d
d      j                         syy)uo   approval_evidence 형식 검증.

    필수 키: approved_by, evidence_path, ts
    Returns (ok, reason).
    )Fz approval_evidence must be a dict>   tsapproved_byevidence_pathFu!   approval_evidence 누락 필드: r*    )Fu+   approval_evidence.approved_by 빈 문자열r+   )Fu-   approval_evidence.evidence_path 빈 문자열r)   )Fu"   approval_evidence.ts 빈 문자열)Tok)
isinstancedictsetkeyssortedr$   strip)evidencerequiredmissings      r   _validate_approval_evidencer7   ;   s     h%85HX]]_--G9&/9JKKK<<r*002C<<,224E<<b!''):r   )approval_evidencec                   |xs dj                         j                         }h d}||vrdd| d| | ||ddS |t        v r/|dd	| d
| ||dddS t        |      \  }}|sdd| | |||ddS dd| |||ddS )u  review thread resolve 가능 여부 판정.

    Parameters
    ----------
    thread_id:
        GitHub review thread ID.
    severity:
        "low" / "medium" / "high" / "critical"
    actor:
        요청자 식별자 (bot name, user login 등).
    approval_evidence:
        chairman approval evidence dict.
        형식: {"approved_by": str, "evidence_path": str, "ts": str}

    Returns
    -------
    dict
        {"ok": bool, "reason": str, "detail": {...}}

    규칙:
    - severity in ("medium", "high", "critical") → approval_evidence 필수.
      없거나 형식 부적합 → ok=False.
    - severity == "low" → evidence 없어도 OK (audit은 별도로 필수).
    r,   >   lowr   r	   r
   Fu   알 수 없는 severity: 'u   '. 허용: )	thread_idseverityactorr-   reasondetailNz
severity='uh   ' 스레드 resolve는 chairman approval_evidence 필수. evidence 없이 resolve 시도 → fail-closed)r;   r<   r=   r8   u!   approval_evidence 형식 불량: Tu   resolve 허용)lowerr3   APPROVAL_REQUIRED_SEVERITIESr7   )r;   r<   r=   r8   valid_severitiesev_ok	ev_reasons          r   can_resolve_threadrF   U   s    > B%%'--/H<''28*KHXGYZ$-8eT
 	
 //$ 
 +E E "+ (")-	  77HIy=i[I!* ("):		 	 "" !2	
	 	r   r%   c        	   
     8   t               }	| ||||||||	d	}
t        |
      }i |
d|i}t        |      }|t        z  }|j                  j                  dd       t        j                  |d      dz   }t        j                  t        |      t        j                  t        j                  z  t        j                  z  d      }	 t        j                  ||j                  d	             t        j                   |       |S # t        j                   |       w xY w)
u  resolve 시도 audit 기록 (JSONL atomic append).

    memory/orchestration-audit/review-thread-resolution.jsonl 에 line append.
    필수 필드 10개: task_id, pr_number, thread_id, severity, actor,
    approval_evidence, result, reason, timestamp, evidence_hash
    )	task_id	pr_numberr;   r<   r=   r8   resultr?   	timestampevidence_hashT)parentsexist_okF)r   
i  r   )r   r   r'   AUDIT_JSONL_RELparentmkdirr   r   r"   openstrO_WRONLYO_APPENDO_CREATwriter   close)rH   rI   r;   r<   r=   r8   rJ   r?   r&   rK   base_recordev_hashr   	work_roottargetlinefds                    r   record_resolution_auditr`      s    $ 
I .
K !-G66_g6F	*I(F
MMt4::f51D8D	VbkkBKK7"**De	LB
T[[)*
M 	s   %D DF)r8   repodry_runr&   c                  | t         j                  j                  dd      }	 t        | |||      }	|	d   s2t	        ||| |||d|	d   |	      }
d|	d   i |	d	   d
t        |
      idS |r&t	        ||| |||dd|	      }
dd| t        |
      ddS |}	 t        j                  dddddt         dd|  gddddd      }|j                  dk(  }|j                  j                         }|j                  j                         }|rd}d}nd}d| }t	        ||| ||||||	      }
||| |t        |
      ddS # t        $ r}d}d}t        |      }Y d }~Rd }~ww xY w)NGH_REPOzJeon-Jonghyuk/dev_workspace)r=   r8   r-   rejectedr?   )	rH   rI   r;   r<   r=   r8   rJ   r?   r&   Fr@   
audit_pathr>   allowedu$   dry_run=True, mutation 호출 생략Tu   dry_run: mutation 호출 생략)r;   rf   ghapigraphqlz-fzquery=z-Fz	threadId=   )capture_outputtexttimeoutshellcheckr   r,   u#   resolveReviewThread mutation 성공u%   resolveReviewThread mutation 실패: )r;   mutation_outputrf   )r"   r#   r$   rF   r`   rT   
subprocessrun_RESOLVE_MUTATION
returncodestdoutr3   stderr	Exception)r;   r<   rH   rI   r=   r8   ra   rb   r&   gaterf   _procmutation_okmutation_outmutation_errexc
mut_result
mut_reasons                      r   resolve_thread_via_graphqlr      s    |zz~~i)FG 85<MD :,/>


 8nGhGs:G
 	
 ,/9


 7$-S_M
 	
 	A ~~eY012	)-
  
 oo*{{((*{{((* 
:

<\NK
 )+
J "+j/
 3   3x s   A/D9 9	EEE)returnrT   )r   r/   r   rT   )N)r&   Optional[Path]r   r   )r4   objectr   ztuple[bool, str])
r;   rT   r<   rT   r=   rT   r8   Optional[dict]r   r/   )rH   rT   rI   intr;   rT   r<   rT   r=   rT   r8   r   rJ   rT   r?   rT   r&   r   r   r   )r;   rT   r<   rT   rH   rT   rI   r   r=   rT   r8   r   ra   zOptional[str]rb   boolr&   r   r   r/   )__doc__
__future__r   r   r   r"   rr   r   r   pathlibr   typingr   	frozensetrB   rP   rt   r   r   r'   r7   rF   r`   r   r   r   r   <module>r      s   #   	  '    ))GH  RS	  E
BV> )-MMM 	M
 &M 
Mt !%.. . 	.
 . . &. . . . 
.p )- $||| 	|
 | | &| | | | 
|r   