# task-2612+2 — AUTO_REMEDIATION: _read_json validate→open TOCTOU symlink-swap 봉합 (non-Critical 자동 수렴 계속)

> **Lv**: Lv.3. **goal_type**: auto_remediation_planner_hardening. **Executor**: dev4-team 비슈누 (key 7943afbe12c12f7d) 1회 한정 — task-2612 계열 원 executor. **TTL**: 3h. **분류**: **AUTO_REMEDIATION_HOLD 자동 수렴**(non-Critical HIGH×1·CRITICAL 0·critical7 false·회장 확인 대기 0·분류 후 멈춤 금지 — feedback-auto-remediation-hold-vs-chair-hold 강화원칙). 문서-only 금지. **callback: 반드시 독립 ANU key c119085addb0f8b7(executor self key 7943afbe12c12f7d 절대 금지·+49 코드 정본).**
> **판정 정본**: `memory/events/task-2612+1.independent-collector-adjudication.json` (Codex CRITICAL 0 · HIGH 1 · NEW_ISSUES none · critical7 false · H2 CLOSED · H1 원 gap 전부 CLOSED·잔여 TOCTOU 만). **+N=원래 goal completion blocker.**

## 1. 잔여 HIGH×1 (task-2612+1 독립 ANU/Codex 재audit 정본 verbatim · non-Critical)

`anu_v3/auto_remediation_planner.py`:
- **H1r (residual)**: `_contained_resolved()` 가 경로를 `resolve()`로 검증한 뒤 `_read_json()` 이 별도 `Path.read_text()` 로 다시 open → 검증과 open 사이 **TOCTOU symlink-swap 윈도**. 공격자가 `CANONICAL_WS_ROOT` 내부 파일 쓰기 권한 보유 시 검증 통과 후 최종 경로 구성요소를 ws-밖 symlink 로 교체해 out-of-scope read(예 `/etc/passwd`) 가능. 원 task-2612 의 `../`·임의 절대경로·기존 symlink·prefix-confusion gap 은 task-2612+1 에서 **전부 CLOSED**(재audit 실증) — 잔여는 이 동시변경 전제 TOCTOU 만.

CRITICAL 0 · critical7 false · 신규 Critical7 0 · H2 CLOSED → non-Critical AUTO_REMEDIATION (회장 원칙: 분류 후 멈추지 말고 자동 수렴).

## 2. 목표 (자동 remediation — validate→open race 봉합)

**용어 명확화**: planner **산출 성격**(plan 골격 생성만·실 dispatch 0·실 코드수정 0) 불변. 본 remediation 은 `_read_json` 입력 read-path 의 **검증·open 원자성 강화**(입력검증 코드 hardening)이며 "plan-only" invariant 와 무모순.

- **H1r 교정**: validate→open 사이 race 제거. 권장 패턴 중 하나로 fail-closed 구현:
  - `os.open(path, O_RDONLY | O_NOFOLLOW)` 로 최종 구성요소 symlink 추종 차단 후, **열린 fd 기준** containment 재검증(`os.fstat` ino/dev 대조 또는 `/proc/self/fd/<fd>` `os.readlink` → `CANONICAL_WS_ROOT` strict 하위 재확인) 후 fd 로 read. 이탈 시 `PathContainmentError`(fail-closed).
  - 또는 디렉터리 구성요소를 `O_NOFOLLOW` 로 단계적 open(openat 패턴)하여 중간 symlink 도 차단.
- 단일 진입점 유지: 모든 JSON read 는 여전히 `_read_json` 단일 helper 경유. `_contained_resolved()` 의 기존 정적 검증(../·절대·prefix-confusion·기존 symlink)은 1차 방어로 보존, fd-기준 재검증을 2차로 추가(defense-in-depth).

## 3. 필수

- 변경 범위: `anu_v3/auto_remediation_planner.py` 의 `_read_json`(+ 필요한 helper 1개) read-path 원자성 hardening **만**. planner 산출 성격 불변(plan 골격 생성만·실 dispatch 0·실 코드수정 0). H2/`_normalize_expected_rel`/`_expected_files`/skeleton **byte-0**(CLOSED 확정 — 재변경 금지).
- `schemas/auto_remediation_plan.schema.json` byte-0 (sha256 `272a6f415b0ddf00bf0c677c3e97691ce548bd8f5e12458053d58e249bc6f430`)
- regression: `tests/regression/test_auto_remediation_planner.py` 에 (a) `O_NOFOLLOW`/fd-재검증으로 최종-구성요소 symlink→ws밖 차단 (b) 기존 ws-하위 read 무회귀 (c) 2604/2605/2609 plan 변환 전수 무회귀 (d) plan-only AST 가드 PASS 케이스 additive. 기존 23 케이스 무회귀.
- Codex 재audit HIGH/CRITICAL 0 일 때만 durable-success write-back

## 4. expected_files allowlist (자기 deliverable 한정)

`anu_v3/auto_remediation_planner.py`(read-path 원자성 hardening 만) · `tests/regression/test_auto_remediation_planner.py`(TOCTOU/O_NOFOLLOW 재현 additive·기존 무회귀) · `memory/events/task-2612+2.{decision,result}.json` · `memory/reports/task-2612+2.md`. 이 외 write 0. **schema·H2 영역·Track A/B/C·task-2610/2611+2/2613·task-2553/2604 multitrack byte-0**. git HEAD `20456b5f83fc039f2fd6f50f4b94095c29b41bfb`·branch `task/task-2553p1-f1-clean-replacement` 전후 EQUAL(ANU Layer-A no-git·커밋 0).

## 5. 금지

planner 산출 성격 변경 · schema 변경 · H2/`_normalize_expected_rel`/`_expected_files` 재변경(CLOSED 확정) · H1r 외 임의 리팩터링 · 2604/2605/2609 plan 변환 동작 변경 · executor self-callback/self-collector/self-adjudication/self-dispatch · PR/branch/main write·merge·credential · premature write-back(Codex HIGH/CRITICAL 0 전) · 타 track/기존 산출물 변조 · 문서-only 완료.

## 6. HOLD_FOR_CHAIR

신규 Critical7 또는 shared invariant 파손 시에만 CHAIR_HOLD. 그 외 잔여 non-Critical 은 AUTO_REMEDIATION 자동 수렴 계속(회장 확인 대기 0·멈춤 금지). 본 라운드 HIGH/CRITICAL 0 달성 시 +53 durable-success write-back 으로 수렴 종료.

## 7. callback (a) — 독립 ANU key 강제 + fallback 노이즈 0

완료 직후 normal completion callback **ANU key c119085addb0f8b7로만 발사** → 독립 ANU collector 회수·Codex 재audit·adjudication. collector 는 adjudication 완료 **즉시 본 task ANU fallback cron cancel-on-success 제거**(노이즈 0). Codex 재audit HIGH/CRITICAL 0 일 때만 +53 durable-success write-back. **잔여 non-Critical HIGH 시 회장 보고 없이 task-2612+3 자동 수렴 계속**. executor self key 7943afbe12c12f7d 절대 금지(+49 코드 정본). ANU fallback=ANU key·안전망 한정·진행 트리거 아님·정상수렴 시 self-cancel. authoritative 판정원=독립 ANU only.

## 8. 9-R (확정 — 본 절 본문 우선 · PRE-DISPATCH SPEC)

본 task md 는 dispatch 전 작업 명세(spec). 산출물 부재·baseline 일치 정상. lint 기준=spec 정합성(구현 검증 아님). task-2612+1 독립 ANU/Codex 재audit 정본(H2 CLOSED·H1 원 gap 전부 CLOSED·잔여 TOCTOU HIGH 1·CRITICAL 0·critical7 false) 을 verbatim 승계. H1r 한정·산출 성격 불변·schema byte-0·H2 영역 byte-0·O_NOFOLLOW+fd-재검증 race 봉합·기존 23 regression 무회귀·premature write-back gate·fallback cancel-on-success·잔여 시 자동 수렴 계속·자기 deliverable 한정·self-* 금지·ANU-key callback 정합. **ANU-Codex re-lint GO_READY 확정 후 dispatch**. ANU key 로 dev4 비슈누 1회 위임. (자동 수렴 — 회장 보고 없이 진행.)
