# credential scan 3계층 doctrine (회장 2026-05-22, PR #132)

merge/PR credential 스캔은 "키 문자열 발견 = fail"이 아니라 **3계층 분리**. 조건의 취지는 **신규 secret 유입 차단**이지 기존 시스템 식별 상수의 expected_files 내부 재사용 차단이 아니다.

## 1. BLOCKING_SECRET (merge 차단 · 즉시 회장 보고)
- `ghp_` / `ghs_` / PAT (GitHub 토큰)
- PEM / private key (`-----BEGIN ... PRIVATE KEY-----`)
- AWS / Cloud secret
- 새로 유입된 실제 인증 secret · 신규 권한/secret expansion · 외부 노출 위험 증가

## 2. EXISTING_SYSTEM_IDENTIFIER (merge 가능 · raw credential fail 아님)
- origin/main에 이미 존재하는 ANU key(`c119085addb0f8b7`) / executor(dev) key
- denylist / fail-closed 테스트용 self-key 예시 상수 (예: `EXECUTOR_SELF_KEY_FORBIDDEN`, "발사 금지 대상")
- fixture evidence에 이미 포함된 식별 상수
- 이미 머지된 코드 상수(`DEFAULT_ANU_KEYS = frozenset({"c119085addb0f8b7"})`)와 동일 패턴

## 3. NET_NEW_IDENTIFIER_EXPOSURE (merge 전 별도 보고)
- 기존 origin/main에 없던 봇 key 식별자가 새로 추가되는 경우

## 적용 절차
1. diff에서 **BLOCKING_SECRET 클래스만 hard-block**
2. 봇 key 식별자 발견 시 `git grep origin/main`으로 기존존재 교차확인 → 있으면 통과(2계층), 없으면 보고(3계층)
3. "키 문자열 1건 발견 = fail" 단순 룰 금지. 핵심 판별 = **net-new exposure 여부**
4. credential 게이트는 독단 금지 영역 → NET_NEW 의심 시 fail-closed + 회장 보고

## 실증 (PR #132 L1+L2)
`c119085addb0f8b7`(ANU)·`1e41a2324a3ccdd0`(dev6 페룬 denylist self-key 예시)가 L1/L2 소스 상수로 검출됐으나, 둘 다 origin/main 다수 파일 + 머지된 L3(`DEFAULT_ANU_KEYS`·task-2625/2628+1 fixture)에 이미 존재 → EXISTING_SYSTEM_IDENTIFIER 판정, BLOCKING_SECRET(ghp_/PEM) 신규유입 0 → 회장 A안 merge 승인(94540f67).
