탈퇴 시 보관 중이던 GitHub access token 을 폐기 - #198
Merged
Merged
Conversation
deleteAccount 는 soft delete 만 하고 encrypted_github_access_token 을 그대로 남겼다. 이 토큰은 `repo` 스코프로 발급된다 — 비공개 레포까지 읽을 수 있는 살아있는 자격증명이다. hard delete 는 Phase 2 라 실제로는 무기한 남는다. DB 가 유출되면 이미 떠난 사용자들의 비공개 레포까지 열린다. User.withdraw() 가 soft delete 와 토큰 폐기를 함께 한다. hasGithubLink() 가 이미 토큰 유무로 판정하므로, 지운 뒤 GitHub 연동 기능을 타면 NPE 가 아니라 AUTH_GITHUB_NOT_LINKED 로 떨어진다. V22 의 ck_users_provider_identity 가 provider='GITHUB' 인 모든 행에 토큰 NOT NULL 을 요구해 UPDATE 가 거부된다. 제약의 의도는 "살아있는 계정은 provider 에 맞는 식별자를 갖춰야 한다" 이므로 V28 로 삭제된 행을 예외로 둔다 — 유니크 인덱스들(V3·V22)이 이미 `WHERE is_deleted = FALSE` 로 쓰는 규약이다. GitHub 쪽 grant 무효화는 여전히 사용자 몫이다. 우리가 할 수 있는 건 사본을 갖지 않는 것까지다. 테스트는 #197 의 @PostgresRepositoryTest 로 실제 DB 까지 내려간다. V28 을 빼면 CHECK 제약 위반으로 실패하는 것을 확인했다 — 목 기반 테스트로는 잡을 수 없는 종류다.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
문제
UserService.deleteAccount는 soft delete 와 이벤트 발행만 한다.encrypted_github_access_token은 그대로 남는다.이 토큰이 무엇인지가 핵심이다:
read:user user:email **repo**— 비공개 레포까지 읽을 수 있다docs/security.md §5.3의 "30일 후 hard delete" 는 Phase 2 미구현이다즉 "계정을 삭제해 달라"고 한 사용자의 GitHub 접근 권한을 우리가 무기한 들고 있다. DB 가 유출되면 이미 떠난 사람들의 비공개 레포까지 열린다.
수정
User.withdraw()가 soft delete 와 토큰 폐기를 함께 한다.hasGithubLink()가 이미 토큰 유무로 판정하므로(githubId 가 아니라), 지운 뒤 GitHub 연동 기능을 타면 NPE 가 아니라AUTH_GITHUB_NOT_LINKED도메인 에러로 떨어진다. 추가 분기가 필요 없었다.V28 — CHECK 제약 완화가 필요했던 이유
V22 의
ck_users_provider_identity가provider='GITHUB'인 모든 행에 토큰 NOT NULL 을 요구해서, 토큰을 null 로 만드는 UPDATE 가 DB 에서 거부된다.제약의 의도는 "살아있는 계정은 provider 에 맞는 식별자를 갖춰야 한다" 이므로 삭제된 행을 예외로 뒀다. 이건 이 테이블이 이미 쓰는 규약이다 — 유니크 인덱스 V3·V22 가
WHERE is_deleted = FALSE부분 인덱스다.테스트 — #197 인프라의 첫 배당
@PostgresRepositoryTest로 실제 DB 까지 내려간다. 이건 목 기반 테스트로는 잡을 수 없는 종류다 — 엔티티에서 null 로 만드는 건 자바에서 아무 문제 없이 통과하고, DB 제약이 거부하는 건 실제 UPDATE 를 날려야만 보인다.withdrawClearsGithubAccessToken— 폐기 +hasGithubLink()falsesameGithubAccountCanSignUpAgainAfterWithdrawal— 탈퇴 후 같은 GitHub 계정 재가입 (docs/security.md §5.3이 약속한 동작). 부분 유니크 인덱스 덕에 동작하며, 이 회귀 방지선이 지금까지 없었다V28 을 빼고 돌리면 두 테스트 모두
ConstraintViolationException: ... violates check constraint "ck_users_provider_identity"로 실패하는 것을 확인했다.확인했고 문제없던 것
UserDeletionRevokeListener✅UserDeletionShareRevokeListener✅ (그래서 삭제한 세션이 통계·점수 추이에 계속 잡히던 문제 #196 에서findSharedByOwner에 삭제 필터를 넣지 않은 것)범위 밖 — 별도 보고
탈퇴를 실행할 프론트엔드 화면이 없다.
DELETE /api/users/me는 동작하지만 사용자가 도달할 경로가 없다(프론트에서 '탈퇴' 문자열이 자동 생성 타입에만 존재). US-04 가 백엔드만 구현된 상태다. 확인 다이얼로그·데이터 삭제 안내를 포함한 화면이라 기능 단위 작업이므로 이 PR 에 넣지 않고docs/security.md에 미구현으로 명시했다.