# task-2552 — Fine-grained PAT scope/audit/rotation 위험 매트릭스

**범주**: 검증 #3 (사실 검증 1:1)
**작성 시각 UTC**: 2026-05-11
**검증자**: dev1 헤르메스 (사전조사 Lv.1, read-only)

---

## 1. comment-only PAT 가능성 (공식 GitHub docs 기반)

**핵심 사실**: GitHub PR conversation 댓글 (예: `/gemini review`)은 API 차원에서 `POST /repos/{owner}/{repo}/issues/{n}/comments` (issue 댓글 endpoint).
이는 fine-grained PAT의 **"Issues" 권한**으로 게이팅 (PR review 라인 댓글은 "Pull requests" 권한 별개).

### 1.1 최소 권한 표

| Permission | 설정 | 허용/차단 |
|---|---|---|
| Repository → **Issues** | **Read and write** | ✅ PR conversation 댓글 게시 (= `/gemini review` trigger) |
| Repository → Pull requests | **No access** (또는 Read) | ❌ merge / approve / close / reopen / dismiss / request review 차단 |
| Repository → Contents | **No access** | ❌ push / branch 수정 / merge commit 차단 |
| Repository → Workflows | **No access** | ❌ workflow 수정/실행 차단 |
| Repository → Administration | **No access** | ❌ branch protection / settings 차단 |
| Repository → Webhooks | **No access** | ❌ webhook 변경 차단 |
| Repository → Metadata | **Read** (필수, default) | ✅ repo 존재 확인용 |
| Account permissions | **No access** (전부) | ❌ user 설정 변경 차단 |
| Repository selection | **Only select repositories: dev_workspace** | ✅ 다른 repo 침투 차단 |

→ **결론**: comment-only scope **공식 가능**.

### 1.2 차단되는 위험 행동 (PUT/POST endpoint 기준)

| Endpoint | 필요 권한 | comment-only PAT로 차단? |
|---|---|---|
| `PUT /repos/{O}/{R}/pulls/{n}/merge` | Contents:write + PRs:write | ✅ 차단 (둘 다 No access) |
| `POST /repos/{O}/{R}/pulls/{n}/reviews` (approve) | Pull requests:write | ✅ 차단 |
| `PATCH /repos/{O}/{R}/pulls/{n}` (close/reopen/title) | Pull requests:write | ✅ 차단 |
| `POST /repos/{O}/{R}/pulls/{n}/comments` (review line comment) | Pull requests:write | ✅ 차단 |
| `git push` | Contents:write | ✅ 차단 |
| `PUT /repos/{O}/{R}/branches/{b}/protection` | Administration:write | ✅ 차단 |
| `POST /repos/{O}/{R}/issues/{n}/comments` | Issues:write | ❌ 허용 (의도) |

→ merge/approve/close/reopen/push/branch-protection-bypass **모두 0%** 가능.

---

## 2. 위험 매트릭스

| # | 위험 항목 | 가능성 | 영향 | mitigation | 잔여 위험 |
|---|---|---|---|---|---|
| R1 | PAT 평문 노출 (env file 누출) | 중 | 매우 큼 (OWNER 사칭 댓글 무제한 가능) | secret manager (예: GCP Secret Manager) + `.env.keys` git ignore + `0600` 권한 | 노출 시 즉시 revoke 필수 |
| R2 | PAT 만료 누락 | 중 | 무기한 사용 | fine-grained PAT max 366일 + 90일 rotation 정책 | 자동 rotation 미구현 시 운영자 책임 |
| R3 | OWNER 사칭 댓글로 정책/명령 위변조 | 낮음 (comment-only로 한정) | 중 (가짜 ESCALATED, 가짜 §명시 등) | 댓글 prefix lock (예: `[bot-trigger]` magic word) + audit log 검증 | 사회공학 가능성 |
| R4 | rate limit 소진 (5000/h primary, 1000/h secondary on comments) | 낮음 | 중 (다른 OWNER 작업 영향) | dedupe (PR/head당 1회만) + exponential backoff | 비정상 burst 시 운영 차질 |
| R5 | scope 변경 사고 (write 추가) | 매우 낮음 | 매우 큼 | PAT 생성 시 fine-grained 강제 + audit 자동 비교 (월 1회) | 운영자 실수 |
| R6 | log/CI artifact에 token leak | 중 | 매우 큼 | 모든 호출 site에 `sanitize_gate.sanitize_text()` + CI log mask | 신규 호출 site 추가 시 회귀 |
| R7 | webhook delivery 시 다른 App에 노출 | 매우 낮음 | 낮음 | comment body에 token 포함 금지 (당연) | — |
| R8 | OWNER 계정 자체 침해 (PAT는 OWNER user 자산) | 매우 낮음 | 매우 큼 | 2FA + hardware key + PAT 별도 수명 관리 | OWNER 계정 보안 의존 |

---

## 3. audit 요건

| 요건 | 구현 방법 | 본 task에서 검증한 사실 |
|---|---|---|
| token value 절대 비기록 | `sanitize_gate.sanitize_text()` 적용, `ghs_*`/`github_pat_*` 패턴 마스킹 | utils/sanitize_gate 가 이미 존재(추정) — Task B에서 확인 |
| 호출 1건당 audit log | `memory/events/{task}.gemini_trigger_call.jsonl` (PR#, head sha, ts, dedup_key) | 본 task에서 미생성 (Lv.1) |
| dedup key | `sha256(PR# + head_commit_id)` | 검증 #1에서 동일 head에 OWNER 2회 trigger 사례 확인됨(PR#95, PR#100) → dedup 필수 |
| update-branch 후 head 확정 검증 | `gh pr view {n} --json headRefOid` 후 trigger | `merge_queue_executor.py` 패턴 재사용 가능 |

---

## 4. rotation 정책 권고 (회장 결정 항목)

| 항목 | 권고 | 근거 |
|---|---|---|
| 만료 주기 | **90일** (또는 30일) | fine-grained PAT max 366일이지만 OWNER PAT 위험 high → 보수적 |
| rotation 주체 | OWNER 본인 (수동) | PAT 생성 자동화는 회장 §금지 1번 |
| 만료 임박 알림 | D-7, D-1 자동 알림 (`memory/events/owner_pat_expiry.json`) | Task B 구현 |
| 만료 후 동작 | 실패 시 즉시 ESCALATED — `BOT_TOKEN_EXPIRED_OWNER_PAT_REQUIRED` | merge gate 차단 doctrine 일관 |

---

## 5. 본 task 범위 외 (회장 결정 후 진행 가능)

- 실제 PAT 생성: 회장 §금지 1
- 실제 trigger 호출: 회장 §금지 4
- production token 저장: 회장 §금지 3

위 모두 **본 task에서 시도 0건**.

---

## 6. 결론

- comment-only fine-grained PAT scope: **공식 가능 ✅** (Issues:write 단독)
- merge/approve/close/reopen/push/branch-protection-bypass: **0% 가능 ✅** (전부 차단)
- 잔여 위험은 R1, R2, R6, R8 — 모두 운영 정책으로 mitigation 가능
- **scope 측면 BLOCKER 없음**, 단 회장 doctrine 예외 승인 필요.
