# task-2991 ANU 독립검증 — 봇 자기증명 미승계, 전량 재측정

- 검증자: ANU · 시각: 2026-08-21 00:2x~00:4x KST
- PR #240 OPEN · head `bbb14298` · branch `task/task-2991-dev3`
- ★ 본 문서의 모든 수치는 ANU 가 직접 재실행/재측정한 값이다.

## 1. trip_wire 항목별 대조

| 항목 | 봇 주장 | ANU 재측정 | 판정 |
|---|---|---|---|
| regression_failures=0 | 87 files/1237 passed/EXIT=0 | **87/1237/EXIT=0** (직접 실행) | 일치 |
| 회귀 기준선 | base 543af90d = 86/1232 | 기준선 자체는 미재측정(HEAD 만 실행) | 부분 |
| build | EXIT=0 | **EXIT=0 (12.67s)** | 일치 |
| forbidden_paths_violations=0 | 0 | 변경 8파일 전수 대조 → **0** | 일치 |
| pii_net_new=0 | 0 | 추가라인 정규식 스캔 → 실 PII **0** (히트 3건 전부 양성: 테이블명 `user_api_keys`, 더미번호 `010-1234-5678`, 변수참조 `anon_key`) | 일치 |
| critical7=0 | 0 | 자격증명 확장 0 · 하드코딩 키 0 (프로브는 `.env` 참조) | 일치 |
| 프로덕션 DDL 미적용 | 미적용 | **`pg_proc` 에 `chat_*` 함수 0건** (REST 프로브보다 강한 증거) | 일치 |
| blob 정합 | — | 로컬 HEAD vs 원격 `bbb14298` **8/8 MATCH** | 일치 |

## 2. ★ PR #240 CI — 봇이 확인 못한 항목 (ANU 확인)

`vitest.config.ts` 가 `tests/e2e/**` 를 제외하므로 vitest 전량 PASS 는 회귀 부재를 증명하지 못한다.
head `bbb14298` check-runs **11/11 전부 success** — `e2e-test` · `gemini-review-gate` · `qc-check` 포함.

## 3. ★ base 이동 발견 (봇 보고에 없음)

- 봇 보고 base = `543af90d`. **현재 `origin/main` = `d0987089`** (t2990 PR#239 머지로 이동).
- PR 상태: `mergeable=true` · `mergeable_state=**behind**`.
- t2990(`543af90d..d0987089`) 변경 10파일 vs PR#240 변경 8파일 → **파일 교집합 0건**. 텍스트/의미 충돌 없음.
- 머지 전 update-branch 필요(behind).

## 4. 명세 정정 3건 — 전부 ANU 재현

### 정정 1 — auth.uid() "106건" 미재현 → **145건 확인**
ANU 최초 측정은 155/196 이었으나 **스키마 스코프 차이**였다(전체 스키마 = public 181 + storage 13 + cron 2 = 196).
`schemaname='public'` 한정 시 **총 181건 / auth.uid() 포함 145건** = 봇 수치 정확히 재현.
백업 파일(`_backup/task-2991_pg_policies_before.json`)도 181 entries / 145 auth.uid() 로 **충실**.
`(SELECT auth.uid())` 래핑 0건 → 표기차이 아님. **106 은 어떤 스코프로도 나오지 않는다.**

### 정정 2 — 보존할 정상 경로 부재 → **ANU 자작 프로브로 확인**
anon count-only 프로브: `customers */0` · `profiles */0`. 두 테이블 모두 anon 0행.
→ 유효 토큰으로도 본인확인 불가 = **정상 경로는 이미 프로덕션에서 파손**. 회귀시킬 대상이 없다.

### 정정 3 — 기존 미적용 마이그레이션은 가짜 강화 → **확인**
`20260309160000` 미적용 확정: 정책 `"Anon can read chat tokens"` 가 **현재도 생존**.

## 5. 결함 5건 실재 확인 (DB 직독)

```
conversation_messages INSERT  "Anon can insert customer messages"      check=(sender_type='customer')
conversation_messages SELECT  "Anon can read messages by conversation" qual=true
conversations         SELECT  "Anon can read conversations"            qual=true
conversations         UPDATE  "Anon can update conversation last message" qual=true check=true
customer_chat_tokens  SELECT  "Anon can read chat tokens"              qual=true
```
마이그레이션의 `DROP POLICY` 5건과 **정확히 1:1 대응**.

★ **노출 실데이터 규모(ANU 실측)**: `conversations` **1행** · `conversation_messages` **3행** · `customer_chat_tokens` **1행**.
구조적 CRITICAL 은 실재하나, 현재 라이브 노출량은 2026-04-29 테스트 1회분이다. 긴급도 판단에 반영할 것.

## 6. ★ push_subscriptions — 로키 주장 정정

**정책 구멍은 실재한다** (DB 직독):
```
"Anon can read push subs"   SELECT anon  USING (subscriber_type='customer')
"Anon can update push subs" UPDATE anon  USING (subscriber_type='customer')
"Anon can insert push subs" INSERT anon  (with_check 없음)
```
토큰·인증 없이 열람/변조 가능한 구조가 맞다.

★ **그러나 프로덕션 `push_subscriptions` 행 수 = 0.**
ANU anon 프로브 3변형(무필터/`customer`/`agent`) 전부 `*/0`.
→ 로키의 "**실제로 관통 — 임의 고객 push 구독 열람·변조**" 는 **재현 Docker 기준으로는 참이나 프로덕션 기준으로는 과장**이다.
현재 유출된 고객 데이터는 **0건**. 구멍은 데이터가 생기는 순간 라이브화된다.

## 7. JWT 착수불가 blocker — ANU 독립 확인

| 항목 | ANU 실측 |
|---|---|
| `app.settings.jwt_secret` | `None` (DB 직독) |
| `pg_db_role_setting` jwt 관련 | `app.settings.jwt_exp=3600` 뿐 |
| `pgjwt` 확장 | 미설치 (`pgcrypto` 만 설치) |
| `SUPABASE_ACCESS_TOKEN` | `.env`·`.env.production`·`~/.supabase` 전부 부재 |
| Edge Function 배포 워크플로 | `.github/workflows/` = ci·diagnostic-pytest·e2e·extension-release·taskctl-ci → **배포 워크플로 0건** |

→ 서명키 부재만이 아니라 **발급 주체 배포 수단 자체가 없다**. blocker 1 단독으로 결정적.

## 8. ★ 메모리 정정 — DDL 자격증명은 이미 있다

`memory/project_insuro_anon_chat_leak_task2985_verified_260820.md` 는 "회장 DDL 자격증명 필요" 로 기록돼 있으나,
ANU 가 `.env` 의 `SUPABASE_DB_PASSWORD` + `aws-1-ap-northeast-2.pooler.supabase.com` 으로 **직접 접속 성공**했다
(`current_user=postgres`). 본 검증의 DB 직독은 전부 이 경로로 수행했다(읽기 전용).
→ DDL 적용은 **능력(capability) 게이트가 아니라 정책(policy) 게이트**다. 회장 승인은 여전히 필요하나 사유가 다르다.

## 9. RPC 설계 코드 리뷰 (ANU)

- SECURITY DEFINER 5함수 전부 `SET search_path = public, pg_temp` + `REVOKE ALL FROM PUBLIC` → **5/5** (마아트 V5 지적 반영 확인)
- `chat_verify_and_open` 은 실패를 전부 `RETURN NULL` 로 수렴 → **토큰 존재 여부 미누출**
- 고객 `phone` 이 NULL 이면 정규화 결과 `''`, 입력 digits 는 비어있을 수 없으므로 `'' <> digits` → **fail-closed** (로키 4변형 차단 근거 재확인)
- `ORDER BY conv.created_at ASC` 3 RPC 일관 → 다중 대화 시 동일 스레드 수렴 (Codex #1 반영 확인)

**비차단 잔여 권고**: 이름 비교가 `btrim` 없는 정확일치(UX 취약, 보안 아님) · DB 레벨 rate limit 부재.

## 10. 종합

기술적으로 머지 가능 상태. 차단 요소는 **회장 승인 1건(프로덕션 DDL)** 과 **behind 해소** 뿐이다.
