Repository navigation
test: pin who can see which event across every read path - #27
Merged
Merged
Conversation
Add VisibilityMatrixTest: 8 viewers (owner, group member, accepted friend, pending requester, kicked member, other-group member, stranger, anonymous) x 8 read paths, plus PUT/move/DELETE by every non-owner. No leak found. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
sexypoo
commented
Oct 14, 2026
sexypoo
left a comment
Owner
Author
There was a problem hiding this comment.
QA 판정: HUMAN (1라운드)
CI
- web: 통과 / Vercel: 통과 (web 변경 없음)
- api: 실패. 137개 중 1개 실패:
GroupEventAnnouncementTest.otherMembersAreNotifiedOnceAndTheOwnerIsNot. 이 PR의VisibilityMatrixTest85개는 CI에서 모두 통과함.
실패가 이 PR과 무관한가: 그렇다 (원인 기준)
- 이 PR은 테스트 파일 1개(
VisibilityMatrixTest.java)만 추가하고, 프로덕션 코드와 기존 테스트는 건드리지 않음. GroupEventAnnouncementTest는 Spring 컨텍스트·DB 없이 Mockito mock만 쓰는 순수 단위 테스트라 새 테스트와 공유하는 상태가 없음.- CI 로그상 이준(2L)과 박소라(3L)에게 알림이 정확히 2건 저장됐고, 문구 검증만 실패함.
NotificationService.announceGroupEvent가event.getGroups()(HashSet)를 순회하는데Group이 equals/hashCode를 재정의하지 않아 identity hash 순서를 따름 → 이준이 "소친친친" 문구를 받으면 실패. #28 분석과 일치. - QA가 직접
origin/main(이 PR 없음)에서 이 테스트만 3번 돌렸더니 3번 모두 실패함 (로컬 JDK 24). main 코드 자체의 결함임. - 주의: identity hash는 같은 JVM에서 그 전까지 만든 객체 수에 따라 달라지기 때문에, 테스트 클래스가 하나 추가된 것만으로 CI에서 결과가 뒤집혔을 가능성이 높음. 원인은 아니지만 이 PR을 지금 머지하면 main CI가 빨간색이 될 가능성이 높다.
완료 조건 (6/7)
- 보는 사람 × 조회 경로 파라미터화 테스트: 충족 (8×8=64, 이슈의 7명·7경로에 다른 그룹 멤버·그룹 B 경로 추가)
- PRIVATE 비노출: 충족. 단, 그룹 캘린더에서는 "바쁨"이 아니라 아예 빠짐 (이슈 문구보다 엄격, PR 본문에 기록됨)
- GROUP 일정: 충족 (내보내기는 실제 DELETE API로 수행, 그룹 B 멤버 확인)
- FRIENDS 일정: 충족 (요청 대기 중인 사람 403)
- PUBLIC만
/api/public/**, 주인 이메일 미노출: 충족 (모든 200 응답에 이메일 검사) - 남의 일정 PUT/PATCH move/DELETE/GET 4xx: 충족 (7명 × 3 × 5개 일정, DB 불변 확인)
./mvnw testCI 통과: 미충족 (#28 때문)
코드 리뷰
- 보호 경로 변경 없음, 229줄(400 미만),
needs-human라벨 없음. - 기존 테스트 삭제·비활성화 없음. 별도 H2 DB 이름을 써서 다른 테스트와 데이터가 섞이지 않음.
- 사소한 참고(머지 차단 아님): 대기 중 친구 요청은 "상대가 주인에게 보낸" 방향만 있고 "주인이 보낸" 방향은 없음. 후속 보강 거리.
HUMAN인 이유
PR 코드는 문제없지만 CI가 빨간색이고, 그 해결(#28)은 알림 문구 정책(여러 그룹에 속한 사람에게 어느 그룹 이름을 쓸지)에 대한 PM 결정이 필요해서 이 PR 안에서 고칠 일이 아님. 아래 중 사람이 선택해야 함:
- (권장) #28을 먼저 고친 뒤 이 PR을 main에 맞춰 다시 돌리고, 초록색이면 PASS 처리
- 또는 main이 빨간색이 되는 것을 감수하고 지금 머지
- 덧붙여, 비공개 일정이 그룹 캘린더에서 "바쁨"으로 보이지 않고 빠지는 현재 동작을 정책으로 받아들일지도 확인 필요
Owner
Author
|
🤖 오케스트레이터: QA 판정이 HUMAN이라 자동 머지하지 않았습니다.
|
Owner
Author
결정 (고은님 위임 → Claude)비공개 일정은 그룹 캘린더에서 아예 보이지 않고, "함께 되는 시간" 계산에서만 바쁨으로 반영한다를 정책으로 확정합니다.
🤖 Generated with Claude Code |
This branch was successfully deployed
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.
변경 요약
공개 범위(비공개·그룹·친구·전체) 경계를 자동 테스트로 고정합니다 (ROADMAP SEC-010). 테스트만 추가했고, 테스트 중 실제 누출은 발견되지 않아 프로덕션 코드는 바꾸지 않았습니다.
api/src/test/java/app/toogeduler/web/VisibilityMatrixTest.java(@SpringBootTest+ MockMvc + H2, 실제 JWT로 인증)PRIVATE,GROUP(그룹 A),FRIENDS,PUBLIC,GROUP+FRIENDS일정 다섯 개를 가진다. 제목·메모·장소에[SECRET-<종류>]표식을 넣어, 응답 본문에 표식이 있으면 노출로 판정한다.DELETE /api/groups/{id}/members/{userId}로 내보냄) / 다른 그룹(B) 멤버 / 무관한 로그인 사용자 / 비로그인GET /api/events,GET /api/events/{id},GET /api/groups/{A}/events,GET /api/groups/{B}/events,GET /api/friends/{owner}/events,GET /api/public/events,GET /api/public/events/{token},GET /api/groups/{A}/availabilityviewerSeesOnlyWhatTheVisibilityAllows: 8×8 = 64개 조합 파라미터화. 각 조합마다 HTTP 상태, 보여야 할 일정의 제목·메모·장소, 나머지 일정 표식이 없는지, 주인 이메일이 없는지를 확인한다. 기대값 표는 클래스 Javadoc에 있다.nobodyButTheOwnerCanChangeAnEvent: 주인이 아닌 7명 ×PUT/PATCH move/DELETE= 21개 조합. 모든 일정에 대해 4xx(비로그인 401, 그 외 403)가 나오고 DB의 제목·시작시각·공개 범위가 그대로인지 확인한다.availablePeople에서 빠지기만 하고("바쁨"), 응답에 일정 내용은 없다.발견한 것
GET /api/friends/{내 id}/events로 "친구에게 보이는 내 캘린더"를 볼 수 있다(acceptedFriendship이 내 쪽 id와도 일치하기 때문). 본인 일정이라 매트릭스에 그대로 기록만 했다./api/groups/{id}/events)에서 "바쁨" 블록으로도 보이지 않고 아예 빠진다. 가용시간에서만 바쁨으로 반영된다. 이슈의 "바쁨으로만 보임"보다 더 엄격한 동작이라 누출이 아니며, 정책 변경은 범위 밖이라 그대로 뒀다.검증
cd api && ./mvnw -B -q test -Dtest=VisibilityMatrixTest: 85개 통과 (64 + 21)cd api && ./mvnw -B -q test전체: 137개 중 136개 통과. 실패한 1개는 기존GroupEventAnnouncementTest이고 이 PR과 무관하다.origin/main에서 그 테스트만 단독으로 돌려도 로컬(JDK 24)에서 실패하는데, CI(JDK 21)의 main에서는 통과한다.event.getGroups()(HashSet) 순회 순서에 따라 메시지에 들어가는 그룹 이름이 달라지는 것으로 보인다. CI 결과로 확인해야 한다.cd web && npm ci && npm run typecheck && npm run build: 통과 (web은 변경 없음)완료 조건
VisibilityMatrixTest.java에 보는 사람 × 조회 경로 조합이 파라미터화 테스트로 존재한다/api/public/**에 나오며, 응답에 소유자 이메일이 포함되지 않는다PUT/PATCH move/DELETE/GET /api/events/{id}는 4xx를 반환한다./mvnw test가 CI에서 통과한다: 이 PR의 85개 테스트는 CI에서 모두 통과했지만, 기존의 간헐적 실패 테스트GroupEventAnnouncementTest때문에 api 잡이 빨간색이다. 별도 이슈 #28로 분리했다.Closes #16
🤖 Generated with Claude Code