Skip to content

feat(auth): mid-flight 401 만료 세션 투명 재인증 (withReauthRetry, #210)#211

Merged
DaveDev42 merged 1 commit into
mainfrom
agent-a36995e5ddebf75be
Jun 26, 2026
Merged

feat(auth): mid-flight 401 만료 세션 투명 재인증 (withReauthRetry, #210)#211
DaveDev42 merged 1 commit into
mainfrom
agent-a36995e5ddebf75be

Conversation

@DaveDev42

Copy link
Copy Markdown
Contributor

요약

이 PR은 #210 을 닫습니다. 의존: #209 (headless 재인증 인프라) 가 main에 머지된 뒤 base를 main으로 재타겟해야 합니다.

문제 (mid-flight 401 갭)

세션 파일이 있어도 쿠키가 만료된 경우, live API 호출이 TossApiError(401) 을 던지면 기존 코드는 "Session is no longer valid. Run aitcc login again." 을 출력하고 종료했습니다. 크리덴셜이 저장돼 있어도 자동 재인증이 없었습니다.

해결책

Part 1 — TossApiError 게터 추가 (src/api/http.ts):

  • isGeoBlocked: errorCode === '4010' — 지역 차단은 재인증해도 소용없음
  • isExpiredSession: isAuthError && !isGeoBlocked — 진짜 만료된 세션만

Part 2 — withReauthRetry<T> 헬퍼 (src/commands/_shared.ts):

  • 읽기 작업을 감싸 isExpiredSession 에러 시 파일 크리덴셜로 headless 재인증 후 1회 재실행
  • 재인증 carve-out: AITCC_SESSION env, env 크리덴셜(kind: 'env'), geo-block(4010) → 재인증 없이 rethrow
  • ONE reauth + ONE replay만 — 루프 없음
  • AcquireSessionDeps injection seam으로 단위 테스트 가능

Part 3 — 읽기 명령 전체 적용:

  • whoami, app ls/show/status/bundles ls/bundles deployed
  • workspace ls/use/show/partner/terms show/segments ls
  • members ls, notices ls/show/categories
  • me terms show, keys ls, app init (워크스페이스 목록 fetch)

Part 4 — 변이 명령은 의도적으로 제외:

  • app deploy/register, keys create/revoke, members invite/remove
  • workspace terms agree, me terms agree
  • 이중 제출 방지 — 변이 재실행은 안전하지 않음

보안 제약 (유지 확인)

  • SECRET-HANDLING: stderr breadcrumb에 쿠키/크리덴셜/토큰 미포함
  • AITCC_SESSION env 활성 시 자동 재인증 없음
  • env 크리덴셜(AITCC_EMAIL/PASSWORD) → 재인증 없음
  • geo-block(4010) → 재인증 없음
  • 재인증 1회, 재실행 1회 — 루프 없음
  • 브라우저 직접 실행 없음 (headlessLoginFromCredentials 사용)

테스트

  • src/commands/_shared.reauth-retry.test.ts: withReauthRetry 7 케이스 (a~g)
  • src/api/http.test.ts: isGeoBlocked, isExpiredSession 게터 3 케이스 추가
  • 전체 게이트: pnpm typecheck && pnpm lint && pnpm test && pnpm build — 728 tests passed

Closes #210

- TossApiError에 isGeoBlocked(4010), isExpiredSession 게터 추가
- withReauthRetry<T> 헬퍼: 읽기 전용 명령에서 만료 세션 감지 시
  저장된 파일 크리덴셜로 headless 재인증 후 1회 재실행
- 재인증 carve-out: AITCC_SESSION env, 환경변수 크리덴셜, geo-block은 제외
- 읽기 명령 전체 적용: whoami, app ls/show/status/bundles,
  workspace ls/show/partner/terms/segments, members ls,
  notices ls/show/categories, me terms show, keys ls, app init
- 변이 명령은 의도적으로 제외(이중 제출 방지)
- withReauthRetry 단위 테스트(7 케이스) + isExpiredSession/isGeoBlocked 테스트 추가
@DaveDev42
DaveDev42 merged commit a22bc92 into main Jun 26, 2026
1 check passed
@DaveDev42
DaveDev42 deleted the agent-a36995e5ddebf75be branch June 26, 2026 04:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(auth): mid-flight 401 자동 재인증 — 세션 파일은 있으나 쿠키 만료된 흔한 경우 (read 명령만 transparent retry)

1 participant