Skip to content

fix(F-CMN-002): 보안 테스트를 단독으로 돌려도 초록이다 — 인증을 재는데 데이터 때문에 빨갰다 (#611) - #627

Open
hd0rable wants to merge 1 commit into
mainfrom
fix/security-config-test-standalone-611
Open

hd0rable wants to merge 1 commit into
mainfrom
fix/security-config-test-standalone-611

Conversation

@hd0rable

Copy link
Copy Markdown
Member

#611 입니다. 제 파일이고 제가 밟히게 만든 자리입니다.

재현

./gradlew test                                        BUILD SUCCESSFUL
./gradlew test --tests '…security.SecurityConfigTest'  Status expected:<200> but was:<404>   ❗

Dev.permitsEverything/products/{id}/risk-items 를 치는데, 그 경로는 저장된 추출이 DB 에 있어야 200 입니다(#478 이 MockData 폴백을 걷은 뒤로). 전체 실행에서는 앞선 테스트가 H2 에 남긴 것 덕에 초록이고, 혼자 돌리면 404 입니다.

CLAUDE.md 가 그 명령 형태를 공식으로 적어 뒀고, 정책 파일을 만지는 사람이 가장 먼저 치는 것이 --tests '…security.*' 라 이 자리에서 유독 자주 밟힙니다.

❗바로 옆 형제가 같은 이유로 이미 고쳐져 있었습니다

// Prod.allowsAuthenticated — #478 이 남긴 주석
// ❗**데이터에 기대지 않는 경로를 쓴다**. 예전에는 risk-items 를 불렀고 …
//   **인증을 재는 테스트가 카탈로그 상태 때문에 빨개진다** — 재는 것과 깨지는 이유가
//   달라지면 다음 사람이 원인을 여기서 못 찾는다.

그 판단이 옳았는데 형제 쪽만 안 따라왔습니다. 제안하신 ⓐ 가 그 주석과 같은 결론이라 그대로 받았습니다.

고친 모양

Dev    GUARDED_PATHS 셋을 치고 401 이 아님만 단정한다
Prod   같은 셋을 치고 401 을 단정한다

상태를 200 으로 못 박지 않습니다 — 404 든 200 이든 인증 때문이 아니면 통과가 이 테스트의 뜻입니다. 「전면 허용」의 반대말은 401 이지 404 가 아니라는 정리를 그대로 씁니다.

체인이 아예 안 서는 것(전부 500)과 구별하려고 /products 200 하나를 남겼습니다. 목록은 비어도 200 이라 데이터에 안 걸립니다.

경로 목록을 한 벌로 뒀습니다 — 대조는 짝으로만 성립합니다. prod 에서 401 인 것과 dev 에서 401 이 아닌 것이 같은 경로여야 「프로파일이 가른다」가 증명되고, 따로 적으면 한쪽만 늘어난 것을 아무도 모릅니다.

역검증

변이 결과
dev 체인이 인증을 요구하게 한다 permitsEverything 빨강
기준선 초록

전에는 이 테스트가 「인증」과 「데이터」 둘에 걸려 있었습니다. 이제 인증만 재므로, 다음에 진짜로 인증이 깨지면 원인을 한 번 더 가릴 필요가 없습니다.

검증

단독 실행   BUILD SUCCESSFUL     (전: FAILED)
전체        830건 · 실패 0 · skip 0

곁 — CI 에서는 안 보인다는 지적이 맞습니다

ci.yml 이 전체를 돌리므로 CI 는 언제나 초록이었습니다. 단독 실행은 사람 손에서만 일어나서 각자 한 번씩 밟고 각자 넘어갑니다. 이 PR 이후로도 그 갈래를 자동으로 막지는 못합니다 — 클래스 하나만 도는 잡을 따로 두는 것은 값에 비해 비싸다고 봅니다. 대신 이 테스트가 데이터에 안 걸리게 된 것이 그 갈래를 좁힙니다.

Closes #611

./gradlew test --tests '…security.SecurityConfigTest' 가 혼자 돌면 빨갰다. CLAUDE.md 가
그 명령 형태를 공식으로 적어 뒀고, 정책 파일을 만지는 사람이 가장 먼저 치는 것이 그
명령이라 자기 변경과 무관한 빨강을 본다.

  Dev.permitsEverything 이 /products/{id}/risk-items 를 친다
    → 그 경로는 저장된 추출이 DB 에 있어야 200 이다(#478 이 MockData 폴백을 걷은 뒤)
    → 전체 실행에서는 앞선 테스트가 H2 에 남긴 것 덕에 초록
    → 단독 실행에서는 404

  실측   단독 실행   전:  Status expected:<200> but was:<404>
                   후:  BUILD SUCCESSFUL

❗바로 옆 Prod.allowsAuthenticated 가 같은 이유로 이미 고쳐져 있었다(#478) —
"인증을 재는 테스트가 카탈로그 상태 때문에 빨개지면 재는 것과 깨지는 이유가 달라진다".
형제 쪽만 안 따라왔다.

- Dev 는 이제 Prod.rejectsAnonymous 와 같은 세 경로를 보고, 거기서 401 이 아닌 것만
  단정한다. 상태를 200 으로 못 박지 않는 이유는 404 든 200 이든 인증 때문이 아니면
  통과가 이 테스트의 뜻이기 때문이다
- 체인이 아예 안 서는 것(전부 500)과 구별하려고 /products 200 을 하나 남겼다 — 목록은
  비어도 200 이라 데이터에 안 걸린다
- 경로 목록을 GUARDED_PATHS 한 벌로 뒀다. 대조는 짝으로만 성립한다 — prod 에서 401 인
  것과 dev 에서 401 이 아닌 것이 같은 경로여야 "프로파일이 가른다" 가 증명되고, 따로
  적으면 한쪽만 늘어난 것을 아무도 모른다

역검증:
  dev 체인이 인증을 요구하게 한다   permitsEverything 빨강
  기준선                          초록

server 전체 830건 · 실패 0 · skip 0

Closes #611

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@hd0rable hd0rable added 보안 역이용 방지·접근통제·PII·비밀정보 server Spring (:8000) labels Sep 14, 2026
@hd0rable
hd0rable requested a review from junseo2323 September 14, 2026 04:49
@github-actions github-actions Bot added 리뷰대기: 오준서 오준서 이 배정됐고 아직 아무것도 제출하지 않았다 리뷰대기: 정세현 정세현 이 배정됐고 아직 아무것도 제출하지 않았다 labels Sep 14, 2026

@junseo2323 junseo2323 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

승인합니다. 이 빨강을 저는 오늘 실제로 밟았습니다#610 을 리뷰하면서 --tests '…security.*' 를 친 것이 처음 한 일이었고, 나온 것이 정확히 그 줄이었습니다.

(이 PR 전)  SecurityConfigTest$Dev  "전면 허용 — 프론트가 인증 없이 개발할 수 있다"
            java.lang.AssertionError: Status expected:<200> but was:<404>

본문이 "정책 파일을 만지는 사람이 가장 먼저 치는 것" 이라고 한 자리가 바로 그것이라, 이 PR 의 값을 제가 증인으로 서겠습니다. #610 리뷰에도 「이 PR 것이 아닌 빨강」으로 적어 뒀습니다.

재현 — 브랜치에서 사라집니다

단독 실행 (e6a24bb)   ./gradlew test --tests '…security.SecurityConfigTest'   BUILD SUCCESSFUL
전체                  ./gradlew test                                          BUILD SUCCESSFUL · 830건
base                  origin/main 뒤처짐 0커밋

❗변이 둘 — 느슨해지지 않았는지가 이 PR 의 급소입니다

단정이 isOk() 에서 not(401)약해졌으므로, 「약해진 만큼 안 잡히는 것이 생겼나」를 봤습니다.

변이 결과
dev 체인을 anyRequest().authenticated() permitsEverything 빨강
dev 체인을 anyRequest().denyAll() permitsEverything 빨강

둘째가 제가 걱정한 자리입니다 — denyAll 은 401 이 아닌 것으로 떨어질 수 있어서 not(401) 만으로는 통과할 수 있는데, /products 200 앵커가 그걸 뭅니다. 본문은 그 줄을 "체인이 아예 안 서는 것과 구별한다" 로만 적었는데, 실제로는 「전면 허용」이 「401 만 아님」으로 무너지는 것까지 막고 있습니다. 그 줄이 생각보다 일을 더 합니다.

모양 — 형제와 짝이 맞습니다

경로를 GUARDED_PATHS 한 벌로 둔 것이 이 PR 에서 제일 좋은 부분이라고 봅니다. 대조는 짝으로만 성립한다는 것이 맞고, 따로 적혀 있었으면 Prod 에만 경로가 하나 늘어난 날 아무도 모릅니다. #478Prod.allowsAuthenticated 에서 이미 내린 판단을 형제 쪽에 마저 적용한 것이라 새 규칙을 만들지도 않았습니다.

곁 — CI 가 못 잡는다는 정리에 동의합니다

클래스 하나만 도는 잡을 따로 두는 것은 값에 비해 비싸다는 데 동의합니다. 다만 남는 갈래를 한 줄 적어 두면, 이 테스트가 다시 데이터에 걸리는 날(누가 GUARDED_PATHS 에 「저장된 것이 있어야 200」인 경로를 하나 더 넣는 날) 그 사람이 여기 주석을 읽게 됩니다 — 지금 javadoc 이 그 역할을 이미 하고 있어서 따로 요청하지는 않겠습니다.

Closes #611 걸려 있는 것 확인했습니다.

@github-actions github-actions Bot removed the 리뷰대기: 오준서 오준서 이 배정됐고 아직 아무것도 제출하지 않았다 label Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

server Spring (:8000) 리뷰대기: 정세현 정세현 이 배정됐고 아직 아무것도 제출하지 않았다 보안 역이용 방지·접근통제·PII·비밀정보

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SecurityConfigTest 를 단독으로 돌리면 빨갛다 — CLAUDE.md 가 적어 둔 명령이 그 형태다

2 participants