Skip to content

Conversation

@Gyuhyeok99
Copy link
Contributor

관련 이슈

작업 내용

스크린샷 2025-08-10 오전 1 07 26

해당 비밀번호 정책을 추가하였습니다!

  • 비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상

특이 사항

제가 알기로 어노테이션 순서가 상관없는 걸로 아는데

        @Password
        @NotBlank(message = "비밀번호를 입력해주세요.")
        String password

이상하게 이렇게 해야지만 정상 동작하고

        @NotBlank(message = "비밀번호를 입력해주세요.")
        @Password
        String password

이렇게 하니까 동작을 안하더라구요. 혹시 이유 아시는 분 계신가요?

리뷰 요구사항 (선택)

- 비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상
@coderabbitai
Copy link

coderabbitai bot commented Aug 9, 2025

Walkthrough

  1. EmailSignInRequest에 @Email 및 @password 검증이 추가되었습니다.
  2. EmailSignUpTokenRequest의 email에 @notblank 추가 및 @Email 메시지 수정이 이루어졌습니다.
  3. EmailSignUpTokenRequest의 password에 @password 검증이 추가되었습니다.
  4. com.example.solidconnection.auth.dto.validation 패키지에 @password 어노테이션이 새로 생겼습니다.
  5. PasswordValidator 클래스가 추가되어 비밀번호 패턴(영문, 숫자, 특수문자, 최소 8자)을 검증합니다.
  6. PasswordValidatorTest 단위 테스트 클래스가 추가되어 정상 및 비정상 케이스들을 검증합니다.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/main/java/com/example/solidconnection/auth/dto/validation/Password.java (1)

10-20: 주석화와 확장성 개선 제안 (@documented, PARAMETER 타깃 추가, i18n 키 고려)
친절 메모 한 줄. 지금도 잘 동작하지만, 다음 3가지를 더하면 유지보수성이 좋아집니다.

  1. @documented 추가로 Javadoc/Swagger 등 문서 노출을 돕습니다.
  2. 컨트롤러 메서드 파라미터에도 직접 사용할 수 있도록 ElementType.PARAMETER 타깃을 포함합니다.
  3. 메시지를 하드코드 문자열 대신 메시지 키로 바꾸면 다국어(i18n) 대응이 쉬워집니다. 선택입니다.

제안 diff:

 package com.example.solidconnection.auth.dto.validation;

 import jakarta.validation.Constraint;
 import jakarta.validation.Payload;
+import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;

-@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT})
+@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.PARAMETER})
 @Retention(RetentionPolicy.RUNTIME)
 @Constraint(validatedBy = PasswordValidator.class)
+@Documented
 public @interface Password {

-    String message() default "비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상이어야 합니다.";
+    // 선택: 메시지 키 사용 시
+    // String message() default "{validation.password.policy}";
+    String message() default "비밀번호는 영문, 숫자, 특수문자를 포함한 8자리 이상이어야 합니다.";
src/test/java/com/example/solidconnection/auth/dto/validation/PasswordValidatorTest.java (1)

13-41: 테스트 보강: null/blank 허용 케이스 및 파라미터라이즈드 테스트 도입
친절 메모 한 줄. 정책 설계상 @password는 null/blank를 통과(true)시키고 @notblank로 필수값을 책임지므로, 해당 케이스를 명시적으로 검증하면 의도가 더 분명해집니다. 또한 유사 케이스는 파라미터라이즈드 테스트로 모으면 가독성이 좋아집니다.

  1. null/blank 허용 검사 추가:
     @Test
     void 정상_패턴이면_true를_반환한다() {
         assertThat(validator.isValid("abcd123!", null)).isTrue();
     }
+
+    @Test
+    void null_또는_blank면_true를_반환한다() {
+        assertThat(validator.isValid(null, null)).isTrue();
+        assertThat(validator.isValid("", null)).isTrue();
+        assertThat(validator.isValid("   ", null)).isTrue(); // 공백만 포함
+    }
  1. 선택: 각 invalid 케이스를 @ParameterizedTest로 합치면 중복을 줄일 수 있습니다.
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (1)

9-16: 정규식 사전 컴파일로 성능/가독성 개선
친절 메모 한 줄. 매 요청마다 정규식을 컴파일하지 않도록 Pattern을 상수로 만들어 두면 성능과 가독성이 좋아집니다.

제안 diff:

 package com.example.solidconnection.auth.dto.validation;

 import jakarta.validation.ConstraintValidator;
 import jakarta.validation.ConstraintValidatorContext;
+import java.util.regex.Pattern;

 public class PasswordValidator implements ConstraintValidator<Password, String> {

+    private static final Pattern PASSWORD_PATTERN = Pattern.compile(
+        "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$"
+    );
+
     @Override
     public boolean isValid(String value, ConstraintValidatorContext context) {
         if (value == null || value.isBlank()) {
             return true;
         }
-
-        return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$");
+        return PASSWORD_PATTERN.matcher(value).matches();
     }
 }

선택: 최소 길이(예: 8)를 상수로 분리하거나, 어노테이션 속성(min 등)으로 노출하면 정책 변경에 더 유연합니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f4a24a and b110359.

📒 Files selected for processing (5)
  • src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (1 hunks)
  • src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java (2 hunks)
  • src/main/java/com/example/solidconnection/auth/dto/validation/Password.java (1 hunks)
  • src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (1 hunks)
  • src/test/java/com/example/solidconnection/auth/dto/validation/PasswordValidatorTest.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (1)

11-13: Bean Validation 어노테이션 순서 이슈 및 검증 순서 고정 제안

확인 결과 프로젝트 내에 fail-fast 설정은 발견되지 않았습니다.
Bean Validation은 기본적으로 모든 제약을 평가합니다.
하지만 fail-fast 모드가 활성화되면 첫 번째 검증 실패 후 즉시 중단되어 어노테이션 순서에 따라 결과가 달라질 수 있습니다.

변경 사항은 다음과 같습니다:

  1. 원인 설명
    • Bean Validation은 모든 제약을 평가합니다.
    • fail-fast 모드 활성화 시 첫 번째 실패에서 검증이 중단됩니다.
  2. 해결 옵션
    1. fail-fast 모드를 비활성화하여 모든 위반을 수집합니다.
    2. 그룹 시퀀스를 도입하여 검증 순서를 명시적으로 고정합니다.
  3. 구현 예시
    • RequiredChecks, PasswordPolicyChecks 인터페이스를 정의합니다.
    • DTO 필드에 @NotBlank(groups = RequiredChecks.class)@Password(groups = PasswordPolicyChecks.class)를 적용합니다.
    • 클래스 상단에 @GroupSequence({EmailSignInRequest.class, RequiredChecks.class, PasswordPolicyChecks.class})를 추가합니다.

프로젝트 설정을 직접 확인해 주시기 바랍니다.

Comment on lines 9 to 14
@Email(message = "이메일을 입력해주세요.")
String email,

@Password
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
Copy link

@coderabbitai coderabbitai bot Aug 9, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

이메일 제약 조건/메시지 정비 및 비밀번호 검증 순서 고정
친절 메모 한 줄. 지금 이메일은 @Email만 있고 메시지가 “입력해주세요”로 되어 있어 의미가 어긋납니다. 아래처럼 @notblank로 “입력”을, @Email로 “형식”을 검증하도록 분리하는 것을 권장합니다. 또한 위 파일과 동일하게 그룹 시퀀스로 검증 순서를 고정하면 어노테이션 순서 민감도를 제거할 수 있습니다.

  1. 이메일 제약/메시지 정비:
-        @Email(message = "이메일을 입력해주세요.")
+        @NotBlank(message = "이메일을 입력해주세요.")
+        @Email(message = "유효한 이메일 주소를 입력해주세요.")
         String email,
  1. 비밀번호 검증 순서 고정(선택): RequiredChecks → PasswordPolicyChecks 그룹을 위 파일과 동일하게 적용하세요.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Email(message = "이메일을 입력해주세요.")
String email,
@Password
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
@NotBlank(message = "이메일을 입력해주세요.")
@Email(message = "유효한 이메일 주소를 입력해주세요.")
String email,
@Password
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java
around lines 9 to 14, the email validation currently uses only @Email with a
message that implies input is missing, which is misleading. Fix this by adding
@NotBlank with a message for input requirement and keep @Email for format
validation separately. Also, apply group sequence validation to both email and
password fields to enforce a fixed validation order, using RequiredChecks
followed by PasswordPolicyChecks for the password, matching the approach used in
the referenced file.

Copy link
Member

Choose a reason for hiding this comment

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

@Email 어노테이션은 빈 값이 들어와도 예외를 발생시키지 않는 거 같아서, 코드래빗 제안처럼 작성하는 게 좋을 것 같습니다 ! [참고]

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@Gyuhyeok99 Gyuhyeok99 self-assigned this Aug 9, 2025
Copy link
Member

@whqtker whqtker left a comment

Choose a reason for hiding this comment

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

간단한 제안만 코멘트 달았습니다 !!!

Copy link
Member

@whqtker whqtker left a comment

Choose a reason for hiding this comment

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

제가 알기로 어노테이션 순서가 상관없는 걸로 아는데
@password
@notblank(message = "비밀번호를 입력해주세요.")
String password
이상하게 이렇게 해야지만 정상 동작하고
@notblank(message = "비밀번호를 입력해주세요.")
@password
String password
이렇게 하니까 동작을 안하더라구요. 혹시 이유 아시는 분 계신가요?

구체적으로 어떤 상황에서 그런 건가요 ? 제가 해 봤을 땐 동일하게 나오는 거 같긴 합니다.

비밀번호가 빈 값인 경우가 엣지 케이스 같은데, 실행 순서 차이일까요 ...

- @notblank와 @Email을 함께 사용하도록
@Gyuhyeok99
Copy link
Contributor Author

아 빈 값인 경우가 아니라 그냥 @password에 중단점도 찍어보고 로그도 찍어봤는데 중단점도 작동 안하고 로그도 안찍혀있더라구요! 성혁님이 바꾸셨을 땐 동작하셨나요?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java (1)

13-15: 비밀번호 제약 도입 OK, 순서 민감도 제거는 위 파일과 동일하게 적용 권장.

    1. 동일한 그룹 시퀀스(RequiredChecks → PasswordPolicyChecks)를 적용해 두 DTO의 일관성을 확보하세요.
    1. PasswordValidator의 공백 허용, fail_fast 비활성 또는 그룹 시퀀스 적용 중 하나(권장: 그룹 시퀀스)로 순서 의존성을 제거하세요.
    1. 필요 시 @password의 기본 메시지를 “영문/숫자/특수문자 포함 8자 이상” 등 정책을 명시적으로 안내하도록 정비하세요.

원하시면 이 DTO에도 그룹/시퀀스와 테스트를 동일하게 반영하는 커밋 패치를 제안드리겠습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b110359 and 96a494f.

📒 Files selected for processing (2)
  • src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (1 hunks)
  • src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (4)
src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java (2)

3-4: 임포트 추가 적절합니다.

    1. 새 커스텀 제약(@password)과 표준 제약(@Email) 임포트 구성이 명확합니다.
    1. 불필요한 임포트가 없고, 컨벤션에 어긋남이 없습니다.

9-11: 이메일 검증 메시지 분리 적용 잘 하셨습니다.

    1. 입력 누락은 @notblank로, 형식 오류는 @Email로 분리되어 사용자 메시지가 정확합니다.
    1. 공백만 입력되는 케이스도 @notblank가 확실히 차단합니다.
src/main/java/com/example/solidconnection/auth/dto/EmailSignUpTokenRequest.java (2)

3-3: 임포트 추가 적절합니다.

    1. 커스텀 제약(@password) 도입에 필요한 최소 임포트만 추가되어 간결합니다.

9-11: 이메일 제약/메시지 정비가 잘 반영되었습니다.

    1. “입력”은 @notblank, “형식”은 @Email로 역할 분리가 명확합니다.
    1. 사용자 메시지도 SignIn DTO와 일관되어 UX가 좋아졌습니다.

Comment on lines +13 to 15
@Password
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

비밀번호 정책 추가는 OK, “어노테이션 순서 민감도”는 그룹 시퀀스로 해결하세요.

    1. 현상 원인 설명: Bean Validation은 동일 필드의 제약 평가 “순서”를 보장하지 않으며, Hibernate Validator에 fail_fast가 켜져 있으면 첫 위반에서 즉시 중단합니다. 코드상 어노테이션 배치 순서가 검증 순서처럼 보일 수 있으나 이는 구현/리플렉션 차원에서 우연히 고정된 것처럼 보이는 효과입니다.
    1. 재현 조건 추정: PasswordValidator가 null/blank를 허용하지 않거나, fail_fast=true인 경우 어노테이션 배치에 따라 위반 메시지가 달라지거나 기대와 다른 동작처럼 보일 수 있습니다.
    1. 해법 1(권장): 검증 순서를 “그룹 시퀀스”로 고정합니다. RequiredChecks(입력 필수) → PasswordPolicyChecks(복잡도) 순으로 강제하면 어노테이션 배치와 무관해집니다.
    1. 해법 2(보완): PasswordValidator가 null/blank 입력일 때 true를 반환하도록 하여 “입력 여부는 @notblank, 복잡도는 @password”로 역할을 명확히 분리합니다.
    1. 해법 3(환경 설정): fail_fast를 사용하지 않거나(기본 false), 사용한다면 그룹 시퀀스를 반드시 함께 적용합니다.

아래는 DTO 필드의 그룹 지정 예시입니다.

-        @Password
-        @NotBlank(message = "비밀번호를 입력해주세요.")
+        @NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class)
+        @Password(groups = PasswordPolicyChecks.class)
         String password

그리고 그룹/시퀀스 정의 예시입니다(패키지 내 공용 인터페이스로 두고 재사용 권장).

// 공용 그룹
public interface RequiredChecks {}
public interface PasswordPolicyChecks {}

// 검증 순서 고정
import jakarta.validation.GroupSequence;
@GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class})
public interface ValidationSequence {}

컨트롤러 바인딩 시 그룹 시퀀스를 사용하세요.

@PostMapping("/sign-in")
public ResponseEntity<?> signIn(@Validated(ValidationSequence.class) @RequestBody EmailSignInRequest req) { ... }

PasswordValidator 보완 예시(입력 공백 위임):

@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
    if (value == null || value.isBlank()) return true; // 입력 여부는 @NotBlank에 위임
    return PATTERN.matcher(value).matches();
}
    1. 테스트 제안: 어노테이션 순서를 바꿔도 결과가 동일함을 보장하는 파라미터라이즈드 테스트를 추가하세요.

다음 스크립트로 환경/구현 상태를 점검해 주세요.

원하시면 그룹/시퀀스 도입 PR 보조 커밋과 테스트 케이스(순서 의존성 제거)를 바로 생성해드리겠습니다.


🏁 Script executed:

#!/bin/bash
# 1) fail-fast 설정 확인
rg -n -S 'hibernate\.validator\.fail_fast\s*[:=]\s*true' -g 'application*.{yml,properties}'

# 2) PasswordValidator의 공백 처리 확인
rg -n --hidden -S "class\s+PasswordValidator|isValid\(|isBlank\(" -A 8 -B 2

# 3) @Validated에서 그룹/시퀀스 사용 여부 확인
rg -n "@Validated\(" -A 2

# 4) @Password 사용 위치 전수 스캔
rg -n "@Password" -A 2

Length of output: 12161


그룹 시퀀스로 검증 순서를 고정하세요

  1. 그룹/시퀀스 정의
    RequiredChecksPasswordPolicyChecks 인터페이스를 만들고
    @GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class})로 순서를 지정합니다.

  2. DTO 필드에 그룹 지정
    EmailSignInRequestEmailSignUpTokenRequestpassword 필드에
    diff - @Password - @NotBlank(message = "비밀번호를 입력해주세요.") + @NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class) + @Password(groups = PasswordPolicyChecks.class)
    를 적용하세요.

  3. 컨트롤러에 시퀀스 적용
    /sign-in 등 관련 엔드포인트 메서드에
    @Validated(ValidationSequence.class)를 붙여 그룹 시퀀스를 활성화합니다.

  4. 순서 의존성 제거 테스트 추가
    • 어노테이션 배치 순서를 바꿔도 동일한 검증 결과가 나오는지 검증하는 파라미터라이즈드 테스트를 작성하세요.

추가 참고

  • PasswordValidator는 이미 null·빈 문자열을 허용하도록(return true) 구현되어 있어 @NotBlank에 입력 여부 체크를 위임하고 있습니다.
  • hibernate.validator.fail_fast 설정은 기본값(false)으로 확인되어 있으며, 그룹 시퀀스 도입으로 모든 순서 이슈를 완벽히 제거할 수 있습니다.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Password
@NotBlank(message = "비밀번호를 입력해주세요.")
String password
@NotBlank(message = "비밀번호를 입력해주세요.", groups = RequiredChecks.class)
@Password(groups = PasswordPolicyChecks.class)
String password
🤖 Prompt for AI Agents
In src/main/java/com/example/solidconnection/auth/dto/EmailSignInRequest.java
around lines 13 to 15, you need to enforce a fixed validation order using group
sequences. Define two interfaces, RequiredChecks and PasswordPolicyChecks, then
create a ValidationSequence interface annotated with
@GroupSequence({RequiredChecks.class, PasswordPolicyChecks.class}). Annotate the
password field in EmailSignInRequest and EmailSignUpTokenRequest with the
appropriate groups to reflect these interfaces. In the controller methods
handling endpoints like /sign-in, add @Validated(ValidationSequence.class) to
activate the group sequence validation. Finally, add parameterized tests to
verify that changing the annotation order does not affect validation results.

Copy link
Member

@whqtker whqtker left a comment

Choose a reason for hiding this comment

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

변경사항 확인했습니다 ~

아 빈 값인 경우가 아니라 그냥 @password에 중단점도 찍어보고 로그도 찍어봤는데 중단점도 작동 안하고 로그도 안찍혀있더라구요! 성혁님이 바꾸셨을 땐 동작하셨나요?

전 잘 되었던 거 같아요 원인이 뭘까요 ... ㅋㅋㅋㅋ

Copy link
Collaborator

@nayonsoso nayonsoso left a comment

Choose a reason for hiding this comment

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

저도 두 순서로 모두 디버깅 해봤는데요!

{
  "email": "[email protected]",
  "password": "password"
}

이런식으로 해봤을 때, 둘 다 PasswordValidator 를 거쳐가는 것으로 확인했습니다

Comment on lines 4 to 7
import jakarta.validation.ConstraintValidatorContext;


public class PasswordValidator implements ConstraintValidator<Password, String> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

import와 public class 사이의 개행 2줄을
1줄로 해주시면 더 통일될 것 같습니다 😁

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🫡 ccc659e

@Gyuhyeok99
Copy link
Contributor Author

인텔리제이의 버그였을까요,,, 뭘까요

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96a494f and ccc659e.

📒 Files selected for processing (1)
  • src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java (2)

1-6: [1] 스타일/구조는 깔끔합니다.

  • 패키지/임포트/클래스 선언부 구성이 일관적입니다.
  • 이전에 지적되었던 import와 class 사이의 개행도 1줄로 정리되어 통일감이 있습니다. 👍

8-12: @password 검증 순서 및 설정 확인 결과

  1. 검증 로직 설계

    • isValid 메서드는 null 또는 blank를 만나면 true를 반환하도록 설계되어 있어, 존재성 검증은 @NotBlank에 위임됩니다.
  2. fail-fast 옵션 확인

    • application*.yml/application*.propertiesValidatorFactory 설정 전체를 검색한 결과, fail-fast 관련 속성이나 커스텀 ValidatorFactory 빈이 발견되지 않아 기본 순차 검증이 적용 중입니다.
  3. 권장 대응 방안

      1. 현재 구조 유지: 필드에 @NotBlank@Password를 함께 붙이는 간결한 패턴을 그대로 사용
      1. 조합 제약 적용: @Password 애노테이션 내부에 @NotBlank를 포함하고 @ReportAsSingleViolation을 달아 단일 메시지화

Comment on lines +14 to +15
return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$");
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

[3] 정규식 퍼포먼스 개선과 정책 명확화 제안(사전 컴파일 + 유니코드 옵션)

  • String.matches는 호출마다 패턴을 컴파일합니다. 성능과 가독성을 위해 Pattern을 static final로 사전 컴파일하는 편이 좋습니다.
  • 현재 [A-Za-z]는 라틴 알파벳만 허용합니다. 한국어 등 유니코드 문자를 ‘문자’로 인정하려면 \p{L}을 고려하세요.
  • 공백 허용 여부도 정책으로 확정 필요합니다. 지금은 \S 사용으로 공백(스페이스/탭 등)을 금지합니다.
  • 참고: String.matches는 전체 매치를 전제하므로 ^/$는 중복이지만, 가독성 차원에서 유지해도 무방합니다.

적용 diff(ASCII 정책 유지, 사전 컴파일):

@@
-import jakarta.validation.ConstraintValidator;
-import jakarta.validation.ConstraintValidatorContext;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import java.util.regex.Pattern;
@@
-public class PasswordValidator implements ConstraintValidator<Password, String> {
+public class PasswordValidator implements ConstraintValidator<Password, String> {
+
+    private static final Pattern PASSWORD_PATTERN = Pattern.compile(
+        "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\\\"'<>,.?/`~])\\S{8,}$"
+    );
@@
-        return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$");
+        return PASSWORD_PATTERN.matcher(value).matches();

유니코드 ‘문자’ 허용(선택사항) 예시:

  • 최소 하나의 유니코드 문자: (?=.*\p{L})
  • 최소 하나의 숫자: (?=.*\d)
  • 최소 하나의 특수문자: (?=.*[\p{Punct}\p{S}])
  • 공백 금지 및 길이: \S{8,}
private static final Pattern PASSWORD_PATTERN = Pattern.compile(
  "^(?=.*\\p{L})(?=.*\\d)(?=.*[\\p{Punct}\\p{S}])\\S{8,}$"
);

추가로 테스트 케이스 보강을 권장합니다.

  • 길이 경계(정확히 8자).
  • 공백 포함/미포함.
  • 한글/이모지 포함 시 정책 의도에 맞는지.
  • 백슬래시(\) 등 현재 특수문자 집합에 없는 문자의 취급.

정규식 성능 최적화 및 정책 명확화 제안

  1. 정규식 패턴 사전 컴파일
    • String.matches는 호출할 때마다 패턴을 컴파일하므로 매번 오버헤드가 발생합니다.
    • 이를 방지하려면 static final Pattern으로 사전 컴파일하세요.
    • 예시 diff:
      -import jakarta.validation.ConstraintValidator;
      -import jakarta.validation.ConstraintValidatorContext;
      +import jakarta.validation.ConstraintValidator;
      +import jakarta.validation.ConstraintValidatorContext;
      +import java.util.regex.Pattern;
       
       public class PasswordValidator implements ConstraintValidator<Password, String> {
       
      -    public boolean isValid(String value, ConstraintValidatorContext context) {
      -        return value.matches("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\"'<>,.?/`~])\\S{8,}$");
      +    private static final Pattern PASSWORD_PATTERN = Pattern.compile(
      +        "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-={}\\[\\]|:;\\\"'<>,.?/`~])\\S{8,}$"
      +    );
      +
      +    public boolean isValid(String value, ConstraintValidatorContext context) {
      +        return PASSWORD_PATTERN.matcher(value).matches();
          }
  2. 유니코드 문자 허용 고려
    • [A-Za-z]는 라틴 알파벳만 허용합니다.
    • 한국어·한자·이모지 등 모든 언어 문자를 포함하려면 \p{L}을 사용하세요.
    • 예시:
      private static final Pattern PASSWORD_PATTERN = Pattern.compile(
        "^(?=.*\\p{L})(?=.*\\d)(?=.*[\\p{Punct}\\p{S}])\\S{8,}$"
      );
  3. 공백 처리 정책 확정
    • 현재 \S를 사용해 공백(스페이스·탭 등)을 금지하고 있습니다.
    • 실제 서비스 정책에 따라 공백 허용 여부를 명확히 결정하세요.
  4. 테스트 케이스 보강
    • 길이 경계(정확히 8자) 확인 테스트
    • 공백 포함/미포함 시나리오
    • 한글·이모지 포함 시 정책 일치 여부
    • 백슬래시(\) 등 특수문자 처리 검증

위 제안을 반영해 보시고, 패턴 변경이 전체 검증 로직에 미치는 영향을 함께 확인하세요.

🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/auth/dto/validation/PasswordValidator.java
around lines 14-15, the inline String.matches call compiles the regex on every
invocation and restricts letters to ASCII; precompile the regex as a static
final Pattern and use Pattern.matcher(value).matches() instead, replace [A-Za-z]
with \p{L} and use \p{Punct}\p{S} (or an agreed set of allowed special chars) to
allow Unicode letters and symbols, decide and document whether whitespace is
allowed (currently \S forbids it) and adjust the pattern accordingly, and add
unit tests for length boundary (exactly 8), whitespace allowed/forbidden,
Unicode letters (Korean/Chinese), emojis, and tricky special chars to validate
the new policy.

@Gyuhyeok99 Gyuhyeok99 merged commit 289cd89 into solid-connection:develop Aug 12, 2025
2 of 3 checks passed
@Gyuhyeok99 Gyuhyeok99 deleted the feat/434-add-password-policy branch August 12, 2025 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 비밀번호 정책 추가

3 participants