
    Si              	          U d Z ddlZddlmZ ddlmZ d ej                  d      ddd	 ej                  d
      ddd ej                  d      ddd ej                  d      ddd ej                  d      ddd ej                  d      dddZee	ee	ef   f   e
d<   g dZde	dee	ee   f   fdZde	dee	ee   f   fdZd edefd!Zd"ee   de	fd#Zy)$u  외부 AI 전송 전 PII 마스킹 파이프라인 — sanitize 게이트.

redact.py(런타임 로그 마스킹)와 보완적 관계:
- redact.py: 런타임 로그 출력에서 자격증명 자동 마스킹
- sanitize_gate.py: 외부 AI(Codex/Gemini) 전달 전 한국 PII 마스킹

Usage:
    from utils.sanitize_gate import sanitize_text, should_sanitize
    if should_sanitize(level):
        masked_text, detections = sanitize_text(content)
        report = generate_sanitize_report(detections)
    N)Path)Anyu   주민등록번호z\d{6}[-]?\d{7}z[RRN-REDACTED])descriptionpatternreplacementu   전화번호z01[016789]-?\d{3,4}-?\d{4}z[PHONE-REDACTED]u	   이메일z0[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}z[EMAIL-REDACTED]u   API 키z)(?:sk-|ghp_|AKIA|AIza)[A-Za-z0-9_\-]{10,}z[APIKEY-REDACTED]u   계좌번호z\d{3,4}-\d{2,6}-\d{4,6}z[ACCOUNT-REDACTED]u   보험 증권번호z[A-Z]{1,3}\d{8,12}z[POLICY-REDACTED])rrnphoneemailapikeyaccountpolicySANITIZE_PATTERNS)r   r   r	   r
   r   r   textreturnc                     g | }t         D ]^  }t        |   }|d   }|d   }|d   }|||fdt        j                  dt        dt        dt        dt        f
fd	}|j                  ||      }` |fS )
ub  텍스트에서 PII를 마스킹하고 (마스킹된 텍스트, 감지된 항목 리스트)를 반환합니다.

    Args:
        text: PII 마스킹 대상 텍스트

    Returns:
        (마스킹된 텍스트, 감지된 항목 리스트)
        각 감지 항목은 {"type": str, "description": str, "original": str, "replacement": str} 형식
    r   r   r   m_key_desc_replr   c                 R    j                  ||| j                  d      |d       |S )Nr   )typer   originalr   )appendgroup)r   r   r   r   
detectionss       D/home/jay/workspace/.worktrees/task-2117-dev1/utils/sanitize_gate.py_replace_and_recordz*sanitize_text.<locals>._replace_and_recordO   s3      #( !
#(	 L    )_PATTERN_ORDERr   reMatchstrsub)	r   resultkeyconfigr   r   r   r   r   s	           @r   sanitize_textr'   <   s      JF :"3'$Y/!-0!-0 &){Q\	xx	"	14	KN		 0&9':* :r   filepathc                 N    t        |       j                  d      }t        |      S )u/  파일 내용을 읽어 sanitize_text를 적용합니다.

    Args:
        filepath: 읽을 파일 경로

    Returns:
        (마스킹된 텍스트, 감지된 항목 리스트)

    Raises:
        FileNotFoundError: 파일이 존재하지 않을 때
        OSError: 파일 읽기 실패 시
    zutf-8)encoding)r   	read_textr'   )r(   contents     r   sanitize_file_contentr-   a   s&     8n&&&8G!!r   levelc                     | dk\  S )u   Lv.3 이상인 경우만 True를 반환합니다.

    Args:
        level: 작업 레벨 (int). 3 이상이면 sanitize 게이트 활성화.

    Returns:
        level >= 3이면 True, 그 외 False
        )r.   s    r   should_sanitizer2   r   s     A:r   r   c                    | sydddt        |        ddddg}t        | d      D ]  \  }}|j                  d	d      }t        |      d
kD  r|dd
 dt        |      d
z
  z  z   }ndt        |      z  }|j                  d| d|j                  dd       d|j                  dd       d| d|j                  dd       d        |j	                  ddg       dj                  |      S )u   감지 결과를 markdown 형식의 리포트로 변환합니다.

    Args:
        detections: sanitize_text()가 반환한 감지 항목 리스트

    Returns:
        markdown 형식의 리포트 문자열
    uO   ## Sanitize 게이트 리포트

감지된 PII 없음. 외부 AI 전달 안전.u   ## Sanitize 게이트 리포트 u   총 u'   건의 PII 감지 및 마스킹 완료.u5   | # | 유형 | 설명 | 원본 (일부) | 치환값 |z)|---|------|------|------------|--------|   r   r0   N*z| z | `r   z` | r   z` | `r   z` |u@   > PII가 마스킹된 텍스트만 외부 AI에 전달하세요.
)len	enumerategetr   extendjoin)r   linesiitemr   previews         r   generate_sanitize_reportrA   ~   s    b 	*

s:FG
?3E Z+ 

488J+x=1rlSCMA,=%>>GCM)G4,-T$((="2M1N O% ;<CA	


 
LLN	
 99Ur   )__doc__r    pathlibr   typingr   compiler   dictr"   __annotations__r   tuplelistr'   r-   intboolr2   rA   r1   r   r   <module>rL      sT   
   ,2::/0' &2::;<) #2::QR) !2::JK* & 2::89+ -2::34*9!0 4T#s(^+, !H J" "c4:o 6 "J"C "E#tDz/,B ""	3 	4 	(d ( (r   