Skip to content

Conversation

@move-hoon
Copy link
Member

@move-hoon move-hoon commented Aug 19, 2025

🔗 관련 이슈

📘 작업 유형

  • ✨ Feature (기능 추가)
  • 🐞 Bugfix (버그 수정)
  • 🔧 Refactor (코드 리팩토링)
  • ⚙️ Chore (환경 설정)
  • 📝 Docs (문서 작성 및 수정)
  • ✅ Test (기능 테스트)
  • 🎨 style (코드 스타일 수정)

📙 작업 내역

https://techblog.woowahan.com/9232/

밑의 설명을 이해하기 위해서는 위의 블로그를 보고 오시는 것을 추천합니다.

1. actuator path 및 port 변경(Actuator는 서비스 운영에 사용되는 포트와 다른 포트를 사용한다. Actuator Default 경로를 사용하지 않고, 경로를 변경하여 운영한다.)

  • 보안을 위해서 actuator path와 actuator port를 환경변수 처리했습니다.
  • actuator path와 port는 secret 파일에 추가했고, 노션에도 업로드 해두었습니다.

2. Actuator endpoint는 all disable 상태에서 필요한 것만 include하여 화이트리스트 형태로 운영

  • 불필요한 endpoint가 활성화되어 추후 잠재적 위험이 될 수 있어, 기본 설정을 따르지 않겠다는 설정을 해주었습니다.

3. HTTP(WEB) 엔드포인트 설정

  • HTTP(WEB)은 health endpoint만이 유일하게 기본적으로 expose되어 있기에 info, health, metrics, prometheus를 추가해주었습니다.

4. JMX형태로 Actuator 사용이 필요하지 않을 경우, 반드시 disable한다.

  • JMX는 Default로 expose되어있는 endpoint가 많기 때문에, 사용하지 않음에도 enable 시켜두면 잠재적 위험이 될 수 있어서 비활성화 해두었습니다.

5. Actuator에 접근할 때에는, 인증되었으며 권한이 있는 사용자만이 접근가능하도록 제어한다?

  • 이 부분은 적용하지 않았습니다. (민우님의 의견도 궁금해요!)
  • 설정을 하면 보안상 이점이 있을 수 있지만, 이미 Actuator 포트와 경로를 환경변수로 처리했기 때문에 굳이 설정을 추가하지 않아도 될 것 같다고 판단했습니다.
  • 만약 인증·권한 설정을 추가하면, 요청 시 토큰을 헤더에 담아야 하고, 만료일을 길게 설정하더라도 관리포인트가 늘어난다는 단점이 크게 느껴졌습니다.

🧪 테스트 내역

  • 브라우저/기기에서 동작 확인
  • 엣지 케이스 테스트 완료
  • 기존 기능 영향 없음

🎨 스크린샷 또는 시연 영상 (선택)

기능 미리보기 기능 미리보기
기능 설명 기능 설명

✅ PR 체크리스트

  • 커밋 메시지가 명확합니다
  • PR 제목이 컨벤션에 맞습니다
  • 관련 이슈 번호를 작성했습니다
  • 기능이 정상적으로 작동합니다
  • 불필요한 코드를 제거했습니다

💬 추가 설명 or 리뷰 포인트 (선택)

  • ..

Summary by CodeRabbit

  • 신규 기능

    • Gateway에 Actuator 및 Prometheus 메트릭 노출과 base-path 환경설정 추가
    • 프로덕션 배포 성공/실패 시 Discord 알림 전송 추가
  • 변경

    • 일부 모듈에서 Actuator 의존성 제거해 관측성 Gateway로 집중
    • 보안 설정에서 Actuator 경로를 동적으로 허용 처리
    • 파일 업로드 요청 한도 상향: 최대 요청 크기 30MB
    • JWT 설정을 구성 속성으로 이동, 기본 및 테스트용 만료시간 조정
  • 기타

    • CI 워크플로우에서 테스트용 시크릿 파일 생성을 제거

@coderabbitai
Copy link

coderabbitai bot commented Aug 19, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

여러 모듈에서 Actuator 의존성을 재배치하고 게이트웨이에 Actuator 및 Prometheus 레지스트리를 추가했으며, 게이트웨이 보안은 Actuator base-path 기반 화이트리스트로 변경했습니다. 테스트 시크릿 파일 생성/주입 라인을 CI/CD 워크플로우와 설정에서 제거했고, 인프라 설정을 프로필별 YAML로 분리·정리했습니다.

Changes

Cohort / File(s) Summary
CI/CD secrets 정리
.github/workflows/ci-pr.yml, .github/workflows/dev-ci-cd.yml, .github/workflows/prod-ci-cd.yml
테스트 시크릿을 파일로 쓰는 라인(TEST_SECRET_PROPERTIES./secret/application-test-secret.properties) 제거. prod 워크플로우에 Discord 성공/실패 알림 스텝 추가.
Actuator 의존성 재배치
admin/build.gradle.kts, apis/build.gradle.kts, batch/build.gradle.kts, gateway/build.gradle.kts
admin/apis/batch 모듈에서 Spring Boot Actuator 의존성 제거. gateway 모듈에 Actuator 및 Prometheus 레지스트리 의존성 추가.
빌드 상수 추가
buildSrc/src/main/kotlin/Dependencies.kt
Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY 상수 추가.
Gateway 설정/보안 리팩터링
gateway/src/main/kotlin/org/yapp/gateway/config/ActuatorProperties.kt, .../JwtProperties.kt, .../JwtConfig.kt, .../jwt/JwtTokenProvider.kt, .../security/SecurityConfig.kt
@ConfigurationProperties 기반 JwtProperties/ActuatorProperties 추가. JwtConfig/JwtTokenProvider가 JwtProperties를 사용하도록 변경. SecurityConfig가 ActuatorProperties.basePath를 이용해 동적 화이트리스트 구성(정적 "/actuator/**" 제거).
Gateway 리소스 추가/수정
gateway/src/main/resources/application-web.yml, gateway/src/main/resources/application-jwt.yml
Actuator 노출·포트·base-path 설정 문서 추가(기본 및 test 프로필). JWT 만료 설정 기본값을 Duration으로 변경하고 test 전용 문서 추가.
APIs 설정 정리
apis/src/main/resources/application.yml
spring.profiles.group에 crosscutting/web 추가. test 환경에서 비밀 파일 import 제거 및 일부 외부 설정(Aladin/OAuth) 제거. multipart max-request-size 30MB 추가.
Infra AOP 패키지 이동
infra/src/main/kotlin/org/yapp/infra/aop/aspect/ControllerLoggingAspect.kt, infra/src/main/kotlin/org/yapp/infra/aop/aspect/ServiceLoggingAspect.kt, infra/src/main/kotlin/org/yapp/infra/config/internal/aop/AopConfig.kt, infra/src/main/kotlin/org/yapp/infra/config/internal/aop/LoggingAopProperties.kt
LoggingAopProperties의 패키지 경로를 org.yapp.infra.config.internal.aop로 이동하고 관련 import 조정.
Infra 설정 분리/정리
infra/src/main/resources/application-crosscutting.yml, .../application-external.yml, .../application-redis.yml, .../application-persistence.yml
crosscutting/test 프로필 파일 추가, external/redis에 test 프로필 오버라이드 추가. persistence에서 cache 및 logging.aop 블록 제거 및 Flyway 경로 중 db/seeddb/reed 변경.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client as Client
  participant GW as Gateway
  participant Sec as SecurityFilterChain
  participant Act as Actuator

  rect rgba(235,245,220,0.35)
  note right of GW: Actuator base-path (management.endpoints.web.base-path)는\napplication-web.yml에 설정됨
  Client->>GW: GET {ACTUATOR_BASE_PATH}/prometheus
  GW->>Sec: 인증/인가 검사 (whitelistUrls 포함)
  alt 요청 경로가 whitelist에 포함
    Sec-->>GW: 허용(permitAll)
    GW->>Act: Actuator /prometheus 핸들러 호출
    Act-->>Client: metrics 응답 (text/plain)
  else 권한 필요
    Sec-->>Client: 401/403
  end
  end
Loading
sequenceDiagram
  autonumber
  participant Config as Config Files
  participant Context as Spring Context
  participant GW as Gateway Beans

  rect rgba(220,235,245,0.35)
  note right of Config: application-jwt.yml / application-web.yml
  Config-->>Context: jwt.*, management.endpoints.web.* 바인딩
  Context-->>GW: JwtProperties, ActuatorProperties 빈 주입
  GW->>GW: JwtConfig/JwtTokenProvider가 JwtProperties 사용
  GW->>GW: SecurityConfig가 ActuatorProperties.basePath로 whitelist 생성
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
Spring Actuator 보안 강화 (#105) SecurityConfig가 Actuator 경로를 동적 화이트리스트로 처리하도록 변경했으나, 추가 인증·권한 정책(예: actuator 민감 엔드포인트에 대한 별도 인증/권한 제한, IP 제한, 관리 전용 포트 강제 등)이 적용되었는지 명확하지 않음.
Prometheus 설정 추가 (#105) Gateway에 Micrometer Prometheus 레지스트리 의존성 추가 및 actuator에 prometheus 노출 설정이 application-web.yml에 포함되어 있음.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
CI 워크플로우: 테스트 시크릿 파일 주입 제거 (.github/workflows/ci-pr.yml, .github/workflows/dev-ci-cd.yml) 이슈 #105(Actuator 보안/Prometheus)에 대한 요구사항과 직접 관련 없음—CI 시크릿 주입 정책 변경은 범위 외.
Flyway locations 경로 변경(db/seed → db/reed) (infra/src/main/resources/application-persistence.yml) 마이그레이션 경로 변경은 Actuator/Prometheus 기능과 무관하며 오타 가능성 있어 범위 외.
multipart max-request-size 추가 (apis/src/main/resources/application.yml) 업로드 파일 사이즈 설정 변경은 Actuator/Prometheus 목적과 관련 없음.
외부 API/OAuth 테스트 프로필 오버라이드 추가 (infra/src/main/resources/application-external.yml) 테스트용 외부 API 키·OAuth 오버라이드는 Actuator/Prometheus 기능과 직접 관련 없음.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f247dab and 8b5f7f2.

📒 Files selected for processing (7)
  • .github/workflows/close-jira-issue.yml (1 hunks)
  • .github/workflows/prod-ci-cd.yml (1 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/config/JwtConfig.kt (4 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt (1 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt (2 hunks)
  • gateway/src/main/resources/application-jwt.yml (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch BOOK-277-feature/#105

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.
    • 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.
  • 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 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/Issue comments)

Type @coderabbitai help to get the list of available commands.

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.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apis/src/main/resources/application.yml (1)

31-32: multipart 용량 설정 재확인 및 지연 파싱(resolve-lazily) 제안

현재 파일 최대용량 10MB, 요청 최대용량 30MB로 설정되어 있어, 다중 파일 업로드(예: 3개 × 10MB)는 허용되지만 단일 파일 20MB는 거부됩니다. 의도한 정책인지 확인 부탁드립니다. 대용량 업로드의 리소스 낭비를 줄이기 위해 지연 파싱도 고려해볼 수 있습니다.

지연 파싱 추가 예시:

   servlet:
     multipart:
       max-file-size: 10MB
       max-request-size: 30MB
+      resolve-lazily: true
infra/src/main/resources/application-crosscutting.yml (1)

1-28: 경고: application-crosscutting.yml가 자동 로드되지 않습니다 — 명시적 import 필요

현재 infra/src/main/resources/application-crosscutting.yml 파일은 Spring Boot가 기본으로 로드하지 않아, 안에 정의된 logging.aop.* 설정이 적용되지 않습니다.
다음 중 하나를 선택해 수정해주세요:

• 메인 application.yml (또는 프로파일별 YAML)에 import 추가

spring:
  config:
    import: "classpath:application-crosscutting.yml"

• 파일명을 application.yml / application-<profile>.yml 규칙으로 변경

위치:

  • infra/src/main/resources/application-crosscutting.yml

필요 시 어떤 파일에 import를 추가할지 함께 검토해 드리겠습니다.

gateway/src/main/kotlin/org/yapp/gateway/config/JwtConfig.kt (1)

67-71: SecretKeySpec 알고리즘 표준명 사용 및 macAlgorithm 명시 필요

현재 SecretKeySpec(jwtProperties.secretKey.toByteArray(), SIGNATURE_ALGORITHM.name)에서 SIGNATURE_ALGORITHM.name이 JOSE 표기인 "HS256"을 반환하여, JCA 표준 알고리즘 명인 "HmacSHA256"과 불일치합니다. 런타임에 따라 서명 검증 오류나 예기치 않은 동작을 유발할 수 있으므로 아래와 같이 수정해 주세요.

  • 대상 파일:
    • gateway/src/main/kotlin/org/yapp/gateway/config/JwtConfig.kt
  • 대상 메서드:
    • jwtDecoder()

수정 제안(diff):

-       val secretKeySpec = SecretKeySpec(jwtProperties.secretKey.toByteArray(), SIGNATURE_ALGORITHM.name)
-       val decoder = NimbusJwtDecoder.withSecretKey(secretKeySpec).build()
+       val secretKeySpec = SecretKeySpec(jwtProperties.secretKey.toByteArray(), "HmacSHA256")
+       val decoder = NimbusJwtDecoder
+           .withSecretKey(secretKeySpec)
+           .macAlgorithm(SIGNATURE_ALGORITHM) // HS256 명시
+           .build()

추가 권장사항:

  • HS256 사용 시 비밀키는 최소 32바이트 이상이어야 합니다. (require(jwtProperties.secretKey.toByteArray().size >= 32))
  • 변경 후 통합 테스트를 통해 JWT 발급/검증 경로가 정상 동작하는지 확인해 주세요.
gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt (1)

26-33: 만료 시간 표현을 Duration 기반으로 전환 제안

초 단위 Long보다 Duration 타입을 사용하면 설정값 표현(“15m”, “2h”)이 명확해지고 오입력(밀리초/초 혼동)을 줄일 수 있습니다. 아래와 같이 제안합니다.

-    fun generateAccessToken(userId: UUID, roles: List<Role>): String {
+    fun generateAccessToken(userId: UUID, roles: List<Role>): String {
         val roleStrings = roles.map { it.key }
         val claims = mapOf(
             JwtConstants.ROLES_CLAIM to roleStrings,
             TOKEN_TYPE_CLAIM to ACCESS_TOKEN_TYPE
         )
-        return generateToken(userId.toString(), jwtProperties.accessTokenExpiration, claims)
+        return generateToken(userId.toString(), jwtProperties.accessTokenExpiration, claims)
     }
@@
-    fun generateRefreshToken(userId: UUID): String {
+    fun generateRefreshToken(userId: UUID): String {
         val claims = mapOf(TOKEN_TYPE_CLAIM to REFRESH_TOKEN_TYPE)
-        return generateToken(userId.toString(), jwtProperties.refreshTokenExpiration, claims)
+        return generateToken(userId.toString(), jwtProperties.refreshTokenExpiration, claims)
     }
@@
-    private fun generateToken(subject: String, expirationSeconds: Long, claims: Map<String, Any>): String {
-        val now = Instant.now()
-        val expiry = now.plusSeconds(expirationSeconds)
+    private fun generateToken(subject: String, expiration: java.time.Duration, claims: Map<String, Any>): String {
+        val now = Instant.now()
+        val expiry = now.plus(expiration)

추가로, JwtProperties의 타입도 Duration으로 맞춰야 합니다(파일 외 변경):

// gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt
@ConfigurationProperties(prefix = "jwt")
data class JwtProperties(
    val secretKey: String,
    val accessTokenExpiration: Duration,
    val refreshTokenExpiration: Duration,
)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0b18ce0 and f247dab.

📒 Files selected for processing (24)
  • .github/workflows/ci-pr.yml (0 hunks)
  • .github/workflows/dev-ci-cd.yml (0 hunks)
  • .github/workflows/prod-ci-cd.yml (0 hunks)
  • admin/build.gradle.kts (0 hunks)
  • apis/build.gradle.kts (0 hunks)
  • apis/src/main/resources/application.yml (1 hunks)
  • batch/build.gradle.kts (0 hunks)
  • buildSrc/src/main/kotlin/Dependencies.kt (1 hunks)
  • gateway/build.gradle.kts (1 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/config/ActuatorProperties.kt (1 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/config/JwtConfig.kt (4 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt (1 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt (3 hunks)
  • gateway/src/main/kotlin/org/yapp/gateway/security/SecurityConfig.kt (3 hunks)
  • gateway/src/main/resources/application-jwt.yml (1 hunks)
  • gateway/src/main/resources/application-web.yml (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/aop/aspect/ControllerLoggingAspect.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/aop/aspect/ServiceLoggingAspect.kt (1 hunks)
  • infra/src/main/kotlin/org/yapp/infra/config/internal/aop/AopConfig.kt (0 hunks)
  • infra/src/main/kotlin/org/yapp/infra/config/internal/aop/LoggingAopProperties.kt (1 hunks)
  • infra/src/main/resources/application-crosscutting.yml (1 hunks)
  • infra/src/main/resources/application-external.yml (1 hunks)
  • infra/src/main/resources/application-persistence.yml (1 hunks)
  • infra/src/main/resources/application-redis.yml (1 hunks)
💤 Files with no reviewable changes (7)
  • .github/workflows/prod-ci-cd.yml
  • batch/build.gradle.kts
  • .github/workflows/dev-ci-cd.yml
  • admin/build.gradle.kts
  • .github/workflows/ci-pr.yml
  • infra/src/main/kotlin/org/yapp/infra/config/internal/aop/AopConfig.kt
  • apis/build.gradle.kts
🧰 Additional context used
🪛 detekt (1.23.8)
gateway/src/main/kotlin/org/yapp/gateway/security/SecurityConfig.kt

[warning] 60-60: In most cases using a spread operator causes a full copy of the array to be created before calling a method. This may result in a performance penalty.

(detekt.performance.SpreadOperator)

🔇 Additional comments (17)
infra/src/main/kotlin/org/yapp/infra/config/internal/aop/LoggingAopProperties.kt (1)

1-1: 패키지 이동 영향 없음 — 참조 대상이 동일 패키지에 위치하여 import 불필요

검증 결과 LoggingAopProperties.ktAopConfig.kt가 동일한 패키지(org.yapp.infra.config.internal.aop)에 위치해 있어 별도 import 없이도 정상 참조되며, 다른 Aspect 클래스들(ServiceLoggingAspect, ControllerLoggingAspect)도 이미 새 패키지 경로를 올바르게 사용하고 있습니다. 컴파일 에러 발생 가능성은 없습니다.

Likely an incorrect or invalid review comment.

apis/src/main/resources/application.yml (1)

8-29: profiles.group에 web·crosscutting 모듈 의존성은 확인되나, redis·external 프로필 리소스 미확인 — 의존성/리소스 포함 점검 요청

아래 항목을 확인해 주세요. Spring Boot가 application-{profile}.yml을 classpath에서 로드하려면, 해당 파일이 존재하는 모듈을 apis가 의존해야 합니다.

• application-web.yml
– 위치: gateway/src/main/resources/application-web.yml
apis/build.gradle.ktsproject(Dependencies.Projects.GATEWAY) 의존 확인됨

• application-crosscutting.yml
– 위치: infra/src/main/resources/application-crosscutting.yml
apis/build.gradle.ktsproject(Dependencies.Projects.INFRA) 의존 확인됨

• application-redis.yml
파일 미발견
– 해당 파일을 포함하는 모듈과 apis 모듈의 의존 등록 여부 점검 필요

• application-external.yml
파일 미발견
– 해당 파일을 포함하는 모듈과 apis 모듈의 의존 등록 여부 점검 필요

위 리소스가 누락돼 있으면, 프로필을 지정해도 설정이 적용되지 않습니다. 파일 위치와 apis 모듈의 build.gradle(.kts)에 올바른 implementation(project(...)) 의존을 추가해 주시기 바랍니다.

infra/src/main/resources/application-external.yml (2)

15-33: 테스트 프로필에 더미 외부 연동 키 주입: 방향성 좋습니다

실제 키/비밀을 제거하고 테스트 전용 더미 값을 주입하는 접근이 보안과 테스트 안정성 측면에서 적절합니다.


29-33: key-path 프로퍼티 미사용으로 인한 테스트 실패 우려 없음
현재 infra/src 아래에 oauth.apple.key-path를 참조하거나 .p8 키를 즉시 로드하는 로직이 전혀 존재하지 않습니다. 테스트 부트스트랩 시점에 파일 경로 문제로 실패할 가능성도 없습니다. 해당 코멘트는 적용되지 않으므로 무시해 주세요.

Likely an incorrect or invalid review comment.

gateway/src/main/resources/application-jwt.yml (1)

3-4: 만료 시간의 단위 일관성 확인(초 vs 밀리초) — 코드 사용부와 맞춰주세요

YAML 주석상 값은 “초 단위”로 보입니다. JwtProperties는 Long 타입으로 정의되어 있는데, 토큰 생성부(JwtTokenProvider 등)에서 밀리초 기반 API를 사용한다면 곱셈(×1000) 누락으로 만료가 짧게/길게 적용될 수 있습니다. Duration 타입으로의 전환을 권장합니다(아래 JwtProperties.kt 코멘트 참고).

다음 키워드로 코드 내 사용 단위를 확인해 주세요: accessTokenExpiration, refreshTokenExpiration, plusSeconds, ofSeconds, toMillis, ×1000 등.

gateway/build.gradle.kts (2)

3-13: Configuration Properties 메타데이터(processor) 확인

JwtProperties를 @ConfigurationProperties로 사용 중이므로 메타데이터 생성을 위해 configuration-processor가 annotation processor 경로에 포함되어 있는지 확인이 필요합니다. 다른 공통 플러그인에서 처리 중일 수 있으나, 누락 시 IDE 지원/메타데이터가 제한됩니다.

Gradle 구성에서 아래 항목들을 점검해 주세요:

  • Kotlin 프로젝트라면 kapt(또는 ksp)로 processor 연결 여부
  • 혹은 Java 소스가 포함되어 annotationProcessor로 처리되는지 여부

8-11: Actuator 보안/노출 설정 확인 필요

현재 리소스 설정 파일(application.yml, application.properties 등)에 Actuator 보안 및 노출 정책 관련 프로퍼티가 전혀 정의되어 있지 않습니다. 아래 항목들을 적절히 추가·검토해 주세요.

  • management.endpoints.web.exposure.include (또는 exclude)
  • management.endpoints.web.base-path
  • management.server.port
  • management.jmx.enabled=false
  • management.endpoint.health.show-detailsmanagement.endpoint.health.probes

설정 파일에 반영하신 뒤, 애플리케이션이 기대한 방식으로 동작하는지 재확인 부탁드립니다.

infra/src/main/kotlin/org/yapp/infra/aop/aspect/ControllerLoggingAspect.kt (1)

11-11: 패키지 경로 리팩터링 반영 확인(LGTM)

LoggingAopProperties import 경로 변경이 일관되게 반영되었습니다. 동일 리팩터링이 참조처(ServiceLoggingAspect, AopConfig 등)에도 적용되었는지 최종 확인만 부탁드립니다.

infra/src/main/kotlin/org/yapp/infra/aop/aspect/ServiceLoggingAspect.kt (1)

11-11: 패키지 이동에 따른 import 변경 적합

LoggingAopProperties의 패키지 변경에 맞춘 import 경로 수정이 정확합니다. 런타임 동작에는 영향이 없으며, 동일한 프로퍼티 바인딩을 유지합니다.

gateway/src/main/kotlin/org/yapp/gateway/config/JwtConfig.kt (1)

24-26: JwtProperties 기반 DI 전환 깔끔합니다

설정값을 JwtProperties로 일원화한 점 좋습니다. 프로필별 오버라이드와 테스트 편의성 모두 개선됩니다.

gateway/src/main/resources/application-web.yml (1)

19-29: 테스트 프로필 구성 적절

테스트 프로필에서 고정 포트(8081)와 테스트용 base-path(/actuator-test)로 오버라이드한 점 좋습니다. JMX 노출 차단도 의도에 부합합니다.

gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt (2)

9-19: 구성 바인딩으로 전환 LGTM

@value 분산 주입을 JwtProperties로 응집시킨 방향 좋습니다. 테스트/프로필별 오버라이드도 용이해졌습니다.


26-33: JWT 만료 설정 초 단위로 올바르게 지정됨

  • gateway/src/main/resources/application-jwt.yml
    • access-token-expiration: 1800 (초 단위), 테스트 프로필: 120 (초 단위)
    • refresh-token-expiration: 1209600 (초 단위), 테스트 프로필: 3600 (초 단위)
  • application-web.yml에는 JWT 만료 설정 없음

모든 만료 값이 plusSeconds 호출과 일치하는 초(second) 단위로 설정되어 있음을 확인했습니다. 추가 검증이나 수정을 진행할 필요가 없습니다.

gateway/src/main/kotlin/org/yapp/gateway/security/SecurityConfig.kt (4)

19-26: ActuatorProperties 바인딩/주입 적용 LGTM

@configuration + @EnableConfigurationProperties로 안전하게 바인딩되고, 생성자 주입으로 테스트 편의성도 좋아졌습니다.


61-61: ADMIN 경로 권한 부여 규칙 유지 LGTM

화이트리스트와 분리되어 있어 충돌 가능성 낮습니다.


28-36: favicon 공개 추가 LGTM

문서/리소스 접근에서 404/불필요 인증 회피에 유용합니다.


46-66: 운영 보안 권고: Actuator 관리 엔드포인트 설정 미확인
현재 application.yml 또는 application.properties 어디에서도 management.* 설정이 발견되지 않아, 기본값(모든 엔드포인트 공개, 애플리케이션 포트와 동일한 management 포트)이 적용될 가능성이 높습니다. 운영 환경에서는 반드시 다음 보완을 수행해 주세요:

  • 별도 관리 포트 사용
    management.server.port 를 프라이빗 네트워크/클러스터 전용 포트로 분리
  • 엔드포인트 노출 제한
    management.endpoints.web.exposure.include=health,info,metrics,prometheus
  • 방화벽/IP 허용 목록 적용
    – 인프라 레벨에서 관리 포트 접근을 최소화
  • 추가 권고(옵션)
    – 요청당 rate limit 적용
    – gzip 비활성화로 정보 노출 최소화

설정 유무를 다시 확인하려면 아래 스크립트를 실행해 주세요:

#!/bin/bash
echo "=== YAML 파일에서 management 설정 확인 ==="
rg -n 'management\.' -g '*.yml' .

echo "=== Properties 파일에서 management 설정 확인 ==="
rg -n 'management\.' -g '*.properties' .

Comment on lines +8 to +11
implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)

implementation(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY)

Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Prometheus Registry는 runtimeOnly 의존성으로 두는 편이 일반적입니다

다수의 예제/가이드에서는 micrometer-registry-prometheus를 runtimeOnly로 추가해 컴파일 클래스패스를 최소화합니다. 구현 코드에서 해당 라이브러리 API를 직접 참조하지 않는다면 runtimeOnly로 전환을 고려해 주세요.

-    implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
-
-    implementation(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY)
+    implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
+    runtimeOnly(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY)
📝 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
implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
implementation(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY)
implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
runtimeOnly(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY)
🤖 Prompt for AI Agents
In gateway/build.gradle.kts around lines 8 to 11, the micrometer Prometheus
registry is declared as an implementation dependency but is typically only
needed at runtime; change
implementation(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY) to
runtimeOnly(Dependencies.Prometheus.MICROMETER_PROMETHEUS_REGISTRY) so it is
excluded from the compile classpath (confirm no code references its API at
compile time and adjust if any compile-time usages exist).

Comment on lines +5 to +8
@ConfigurationProperties(prefix = "management.endpoints.web")
data class ActuatorProperties(
val basePath: String
)
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

basePath 바인딩의 안정성 강화(기본값/검증/정규화 제안)

환경변수 미설정 시 애플리케이션이 부팅 실패할 수 있고(필수 필드), 후속 보안 설정(화이트리스트 패턴)에서 선행/후행 슬래시 일관성 문제가 발생할 여지가 있습니다. 기본값, Bean Validation, 정규화된 접근자를 추가해 안정성을 높이는 것을 권장합니다.

적용 제안(diff):

 package org.yapp.gateway.config

 import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.validation.annotation.Validated
+import jakarta.validation.constraints.NotBlank

-@ConfigurationProperties(prefix = "management.endpoints.web")
-data class ActuatorProperties(
-    val basePath: String
-)
+@ConfigurationProperties(prefix = "management.endpoints.web")
+@Validated
+data class ActuatorProperties(
+    @field:NotBlank
+    val basePath: String = "/actuator"
+) {
+    // 보안/화이트리스트 매칭 시 슬래시 일관성 보장
+    val normalizedBasePath: String =
+        basePath.let { if (!it.startsWith("/")) "/$it" else it }.removeSuffix("/")
+}

이렇게 하면:

  • 기본값 제공으로 설정 누락 시에도 안전하게 기동
  • 빈 검증으로 오설정 방지
  • 보안 설정에서 .../basePath/** 패턴 매칭 일관성 보장

Comment on lines 5 to 10
@ConfigurationProperties(prefix = "jwt")
data class JwtProperties(
val secretKey: String,
val accessTokenExpiration: Long,
val refreshTokenExpiration: Long
)
Copy link

@coderabbitai coderabbitai bot Aug 19, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Duration 타입과 Bean Validation(@validated) 적용을 권장합니다

  • 만료 시간은 Long(초) 대신 Duration을 사용하면 단위 혼동을 제거하고, YAML에서 30m/2w 같은 직관적 표기가 가능합니다.
  • 시크릿 키는 공백/누락 방지를 위해 Bean Validation을 붙이는 것이 안전합니다(운영에서 미설정 시 즉시 실패).

아래와 같이 변경을 제안합니다.

 package org.yapp.gateway.config
 
 import org.springframework.boot.context.properties.ConfigurationProperties
+import org.springframework.validation.annotation.Validated
+import jakarta.validation.constraints.NotBlank
+import java.time.Duration
 
-@ConfigurationProperties(prefix = "jwt")
-data class JwtProperties(
-    val secretKey: String,
-    val accessTokenExpiration: Long,
-    val refreshTokenExpiration: Long
-)
+@ConfigurationProperties(prefix = "jwt")
+@Validated
+data class JwtProperties(
+    @field:NotBlank
+    val secretKey: String,
+    val accessTokenExpiration: Duration,
+    val refreshTokenExpiration: Duration,
+)

참고:

  • YAML 예시
    • access-token-expiration: 30m
    • refresh-token-expiration: 2w
  • 클래스 변경 이후 토큰 생성부(JwtTokenProvider 등)에서 Duration을 직접 사용하거나 toSeconds()/toMillis()로 변환해 주세요.

JwtTokenProvider와 JwtConfig에서 JwtProperties 타입 변경 영향(초→Duration)이 문제 없는지 확인 부탁드립니다.


아래 스크립트로 JwtTokenProvider, JwtConfig 클래스 위치와 accessTokenExpiration/refreshTokenExpiration 사용처를 확인하겠습니다.


🏁 Script executed:

#!/bin/bash
set -e

echo "🔍 class JwtTokenProvider 위치:"
rg -n "class JwtTokenProvider" -C3

echo
echo "🔍 class JwtConfig 위치:"
rg -n "class JwtConfig" -C3

echo
echo "🔍 accessTokenExpiration 사용처:"
rg -n "accessTokenExpiration" -C3

echo
echo "🔍 refreshTokenExpiration 사용처:"
rg -n "refreshTokenExpiration" -C3

Length of output: 4625


JwtProperties를 Duration으로 변경 시 JwtTokenProvider 수정 필요

  • JwtProperties
    • LongDuration
    • @Validated + @field:NotBlank 추가
  • JwtTokenProvider
    • generateToken(subject, expirationSeconds: Long, …) 호출부에서 toSeconds()/toMillis() 변환
    • getRefreshTokenExpiration() 반환 타입은 Duration.toSeconds() 호출로 유지

제안된 수정 예시:

--- a/gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt
+++ b/gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt
@@
-@ConfigurationProperties(prefix = "jwt")
-data class JwtProperties(
-    val secretKey: String,
-    val accessTokenExpiration: Long,
-    val refreshTokenExpiration: Long
-)
+@ConfigurationProperties(prefix = "jwt")
+@Validated
+data class JwtProperties(
+    @field:NotBlank
+    val secretKey: String,
+    val accessTokenExpiration: Duration,
+    val refreshTokenExpiration: Duration
+)
--- a/gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt
+++ b/gateway/src/main/kotlin/org/yapp/gateway/jwt/JwtTokenProvider.kt
@@ fun generateAccessToken(userId: UUID): String {
-    return generateToken(userId.toString(), jwtProperties.accessTokenExpiration, claims)
+    return generateToken(userId.toString(), jwtProperties.accessTokenExpiration.toSeconds(), claims)
@@ fun generateRefreshToken(userId: UUID): String {
-    return generateToken(userId.toString(), jwtProperties.refreshTokenExpiration, claims)
+    return generateToken(userId.toString(), jwtProperties.refreshTokenExpiration.toSeconds(), claims)
@@ fun getRefreshTokenExpiration(): Long {
-    return jwtProperties.refreshTokenExpiration
+    return jwtProperties.refreshTokenExpiration.toSeconds()
}

위 변경 후 JwtConfig는 기존대로 @EnableConfigurationProperties(JwtProperties::class)만으로 동작합니다.

🤖 Prompt for AI Agents
In gateway/src/main/kotlin/org/yapp/gateway/config/JwtProperties.kt around lines
5 to 10, change the property types from Long to java.time.Duration and add
validation annotations (@Validated on the class and @field:NotBlank on
secretKey) so configuration binds to Duration values; then update
JwtTokenProvider usages to accept Duration-based expirations (call
expiration.toSeconds()/toMillis() where a numeric value is required) and ensure
methods like getRefreshTokenExpiration() return a Long by calling
duration.toSeconds(); JwtConfig can remain using
@EnableConfigurationProperties(JwtProperties::class).

Copy link
Member

Choose a reason for hiding this comment

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

환경변수로 이부분들이 셋팅되지 않았을 때 확인할 수 있도록 해주는 에러문구가 나타나면 좋을 것 같아요 ex) validation check하는부분이라던지..?

Copy link

Choose a reason for hiding this comment

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

@minwoo1999 정확한 지적입니다! 환경변수 미설정으로 인한 문제를 조기에 발견하는 것이 매우 중요하네요.

Bean Validation을 추가하면 애플리케이션 시작 시점에 명확한 에러 메시지가 나타납니다:

package org.yapp.gateway.config

import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.validation.annotation.Validated
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.Positive
import java.time.Duration

@ConfigurationProperties(prefix = "jwt")
@Validated
data class JwtProperties(
    @field:NotBlank(message = "JWT secret key must not be blank. Check JWT_SECRET_KEY environment variable.")
    val secretKey: String,
    
    @field:Positive(message = "Access token expiration must be positive. Check JWT_ACCESS_TOKEN_EXPIRATION environment variable.")
    val accessTokenExpiration: Duration,
    
    @field:Positive(message = "Refresh token expiration must be positive. Check JWT_REFRESH_TOKEN_EXPIRATION environment variable.")
    val refreshTokenExpiration: Duration
)

이렇게 하면 환경변수가 누락되거나 잘못 설정되었을 때 애플리케이션 시작 단계에서 다음과 같은 명확한 에러가 출력됩니다:

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.yapp.gateway.config.JwtProperties failed:

Property: jwt.secretKey
Value: ""
Reason: JWT secret key must not be blank. Check JWT_SECRET_KEY environment variable.

이는 배포 시 환경변수 설정 누락을 즉시 발견할 수 있게 해주어 운영 환경에서의 문제를 사전에 방지할 수 있습니다.

🐰
∩───∩
( ◕ ◕ )
\ ___ / validation으로 안전하게!
\ /
-----

Comment on lines 12 to 15
jwt:
secret-key: this-is-a-simple-key-for-testing-purpose-only
access-token-expiration: 120 # 2 minute (초 단위, 테스트용 짧게 설정)
refresh-token-expiration: 3600 # 1 hour (초 단위, 테스트용 짧게 설정)
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

테스트 시크릿 키 하드코딩 관리 방안 점검 필요

테스트 용도라 하더라도 하드코딩된 시크릿이 우발적으로 다른 환경에 주입되지 않도록 관리가 필요합니다. 최소한 test 프로필에서만 로드되도록 위 import/프로필 문제를 우선 해결해 주세요. 추가로, 테스트 전용 application-test.yml로 분리하거나 CI에서만 주입하는 환경 변수/ConfigMap로 대체하는 방안도 고려해 볼 만합니다.

테스트 실행 시 활성 프로필이 test로 지정되는지, 그리고 test 외 환경에서 해당 값이 노출되지 않는지 확인 부탁드립니다.

🤖 Prompt for AI Agents
In gateway/src/main/resources/application-jwt.yml around lines 12 to 15, the JWT
secret is hardcoded for testing and may be loaded into non-test environments;
remove the hardcoded value from this common file and instead (a) create
application-test.yml with the secret-key set there or (b) replace the value with
a placeholder that reads from an environment variable/ConfigMap (e.g.
${JWT_SECRET:}) so production configs never contain the test secret, update test
configuration to activate the "test" profile during test runs (e.g. test
framework or CI sets spring.profiles.active=test) and add a verification step to
CI or local test setup to assert the active profile is "test" and that
application-jwt.yml no longer exposes the secret in non-test runs.

Comment on lines +1 to +12
management:
server:
port: ${ACTUATOR_PORT}
endpoints:
jmx:
exposure:
exclude: "*"
web:
exposure:
include: info, health, metrics, prometheus
base-path: ${ACTUATOR_PATH}

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

Actuator 포트/경로 보안 강화 제안(바인딩 기본값, 루프백 바인딩, 노출 축소)

현 설정은 의도대로 별도 포트/경로로 분리되어 좋습니다. 추가로 다음을 고려해 주세요.

  • 루프백 바인딩: 외부 노출 최소화를 위해 기본 주소를 127.0.0.1로 제한
  • 기본값 제공: 환경변수 미설정 시 기동 실패 방지
  • 노출 엔드포인트 축소: info는 빌드/환경 정보 유출 우려가 있을 수 있어 기본 제외 권장(필요 시 내부에서만 확인)

수정 제안(diff):

 management:
   server:
-    port: ${ACTUATOR_PORT}
+    address: 127.0.0.1
+    port: ${ACTUATOR_PORT:8081}
   endpoints:
     jmx:
       exposure:
         exclude: "*"
     web:
       exposure:
         include: info, health, metrics, prometheus
-      base-path: ${ACTUATOR_PATH}
+      base-path: ${ACTUATOR_PATH:/actuator}

선택적 보강:

  • 운영에서 info 제외: include: health, metrics, prometheus
  • readiness/liveness 프로브 필요 시: management.endpoint.health.probes.enabled: true

다음 스크립트로 운영 포트와 충돌(Actuator 포트=애플리케이션 포트) 가능성을 점검해 주세요.


🏁 Script executed:

#!/bin/bash
# gateway 모듈 내 server.port 설정 확인
rg -n -C2 -i 'server:\s*\n\s*port\s*:\s*' gateway/src/main/resources
echo "Actuator port (default doc): ${ACTUATOR_PORT:-<env not set>}"

Length of output: 357


아래 스크립트로 gateway/src/main/resources 내 server.port 설정 여부를 멀티라인 모드로 재확인하고, ACTUATOR_PORT/ACTUATOR_PATH 기본값도 함께 출력해 주세요.


🏁 Script executed:

#!/usr/bin/env bash
# gateway 모듈의 리소스(YAML)에서 server.port 설정 확인 (multiline 모드)
rg -U -n -C2 'server:\s*\n\s*port\s*:' gateway/src/main/resources/*.yml

# ACTUATOR_PORT, ACTUATOR_PATH 환경변수 기본값 확인
echo "ACTUATOR_PORT 기본값: ${ACTUATOR_PORT:-<env not set>}"
echo "ACTUATOR_PATH 기본값: ${ACTUATOR_PATH:-<env not set>}"

Length of output: 963


아래 스크립트로 gateway/src/main/resources 내 애플리케이션 포트(server.port) 설정을 확인하고, 관리용 포트(8081)와 충돌 가능성을 점검해주세요.


🏁 Script executed:

#!/usr/bin/env bash
# 애플리케이션 server.port 설정 확인
rg -nP --type=yml 'server:\s*\n\s*port\s*:' gateway/src/main/resources/*.yml

# 혹은 dot 표기법 사용 여부 확인
rg -n --type=yml '\bserver\.port\b' -C2 gateway/src/main/resources

Length of output: 264


아래 스크립트로 gateway/src/main/resources 내 모든 YAML 파일에서 애플리케이션용 server.port 설정이 8081(Actuator 포트)과 충돌하지 않는지 재확인해 주세요.


🏁 Script executed:

#!/usr/bin/env bash
# 멀티라인 모드로 `server:\n  port:` 패턴 검색
rg -U -nP '^\s*server:\s*\n\s*port:' gateway/src/main/resources/*.yml

# dot 표기법(`server.port:`) 사용 여부 확인
rg -n 'server\.port:' -C2 gateway/src/main/resources/*.yml

# 결과 없을 시 기본값(8080) 사용 여부 안내
echo "애플리케이션 server.port 미설정 시 기본값: 8080"

Length of output: 593


관리용 포트 이중 정의 확인 및 보안 설정 통합

application-web.yml에서 management.server.port가 두 번 정의되어(라인 3: ${ACTUATOR_PORT}, 라인 21: 8081) 의도한 환경변수 바인딩이 무력화되고 충돌이 발생할 수 있습니다. 중복 정의를 제거하고, 다음과 같이 보안 강화를 적용해 주세요.

  • application-web.yml
    • 중복된 management.server.port 정의 제거
    • address: 127.0.0.1 추가해 루프백 바인딩
    • ${ACTUATOR_PORT:8081} 형태로 기본값 지정
    • base-path: ${ACTUATOR_PATH:/actuator} 형태로 기본값 지정
    • 기본 노출 엔드포인트 축소: include: health, metrics, prometheus (info 제외 권장)
 management:
-  server:
-    port: ${ACTUATOR_PORT}
+  server:
+    address: 127.0.0.1
+    port: ${ACTUATOR_PORT:8081}
   endpoints:
     jmx:
       exposure:
         exclude: "*"
     web:
       exposure:
-        include: info, health, metrics, prometheus
-      base-path: ${ACTUATOR_PATH}
+        include: health, metrics, prometheus
+      base-path: ${ACTUATOR_PATH:/actuator}

선택적 보강:

  • 운영에서 info 완전 제외 시 include: health, metrics, prometheus
  • Readiness/Liveness 프로브 활성화:
    management.endpoint.health.probes.enabled: true
🤖 Prompt for AI Agents
In gateway/src/main/resources/application-web.yml around lines 1 to 12, remove
the duplicate management.server.port declaration and consolidate to a single
entry using a defaulted environment variable (e.g. ${ACTUATOR_PORT:8081}); add
address: 127.0.0.1 to bind to loopback; change base-path to use a defaulted
variable (e.g. ${ACTUATOR_PATH:/actuator}); tighten exposed endpoints to include
only health, metrics, prometheus (remove info); optionally enable
readiness/liveness probes by adding management.endpoint.health.probes.enabled:
true.

max-log-length: 1000
controller:
enabled: true
- classpath:db/reed
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

Flyway locations 변경(db/reed) — 경로 존재 및 마이그레이션 충돌 여부 확인 필요

classpath:db/reed로 위치가 변경되었습니다. 실제 리소스 경로에 해당 디렉터리와 SQL 파일이 존재하는지, 그리고 db/migration과 버전 충돌(중복 버전)이 없는지 확인해 주세요. 다중 location 사용 시 파일명이 겹치면 이행 순서/충돌 문제가 발생할 수 있습니다.

확인 스크립트:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) db/reed 디렉터리 존재 여부"
fd -a -t d 'db/reed' || true

echo
echo "2) db/reed SQL 파일 나열"
fd -a -t f -g '**/resources/db/reed/*.sql' || true

echo
echo "3) db/migration SQL 파일 나열 (충돌 확인 대비)"
fd -a -t f -g '**/resources/db/migration/*.sql' || true

Length of output: 338


Flyway locations(db/reed) 경로 미존재 — 마이그레이션 로드 실패 예상

infra/src/main/resources/application-persistence.yml 25행에서 classpath:db/reed로 변경하였으나, 리포지토리 내에 해당 경로 및 SQL 파일이 존재하지 않습니다. 이대로 배포 시 Flyway가 마이그레이션을 찾지 못해 애플리케이션 실행이 실패할 수 있습니다.

  • 디렉터리 미발견: src/main/resources/db/reed 없음
  • SQL 파일 미발견: src/main/resources/db/reed/*.sql 없음
  • 추가 확인: src/main/resources/db/migration/*.sql에도 동일 버전 파일 없음

해결 방안:

  • db/reed 디렉터리 생성 후 마이그레이션 SQL 파일 추가
  • 또는 application-persistence.yml의 locations 값을 실제 존재하는 경로로 수정
🤖 Prompt for AI Agents
infra/src/main/resources/application-persistence.yml around line 25: Flyway
locations points to non-existent classpath:db/reed so migrations will fail;
either create src/main/resources/db/reed and add your migration SQL files there
(matching Flyway naming/versioning), or update application-persistence.yml to
reference an existing migration folder (e.g., classpath:db/migration) and ensure
the referenced SQL files exist and follow Flyway naming conventions.

Comment on lines +8 to +17
---
spring:
config:
activate:
on-profile: test
data:
redis:
host: localhost
port: 6379
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

CI/로컬 테스트에서 Redis 준비 여부 확인 필요

test 프로필이 로컬 Redis(127.0.0.1:6379, 비밀번호 없음)를 가정합니다. CI나 컨테이너 환경에서 Redis 인스턴스를 제공하지 않으면 통합/환경 테스트가 실패할 수 있습니다. 워크플로우에서 Redis 서비스를 띄우거나, Testcontainers/임베디드 Redis를 사용하도록 되어 있는지 확인해 주세요.

다음 스크립트로 워크플로우/코드에서 Redis 준비 과정을 점검할 수 있습니다:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) GitHub Actions 워크플로우에서 Redis 서비스 사용 여부 탐색"
rg -n -C2 -g '.github/workflows/**' -e 'redis' -e 'services:'

echo
echo "2) 테스트 코드에서 Redis Testcontainers/임베디드 사용 여부 탐색"
rg -n -C3 --type=kt --type=java -e 'testcontainers.*redis' -e 'GenericContainer\\(.*redis' -e 'EmbeddedRedis'

Length of output: 327


아래 스크립트로 .github/workflows 디렉토리 존재 여부 및 워크플로우 내 Redis 서비스 설정, 테스트 코드에서 Testcontainers/Embedded Redis 사용 여부를 재확인해 주세요.


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "=== .github/workflows 디렉토리 존재 여부 확인 ==="
if [ -d ".github/workflows" ]; then
  echo ".github/workflows 디렉토리 발견"
  echo
  echo "=== 워크플로우 내 Redis 키워드 검색 ==="
  rg -n 'redis' .github/workflows || echo "워크플로우에서 'redis' 키워드 미발견"
  echo
  echo "=== 워크플로우 내 services: 검색 ==="
  rg -n 'services:' .github/workflows || echo "워크플로우에서 'services:' 미발견"
else
  echo ".github/workflows 디렉토리가 없습니다."
fi

echo
echo "=== 테스트 코드 내 Testcontainers/Embedded Redis 사용 여부 검색 ==="
rg -n 'testcontainers.*redis' -g '*.java' -g '*.kt' . || echo "Testcontainers Redis 참조 미발견"
rg -n 'GenericContainer\s*\(\s*".*redis' -g '*.java' -g '*.kt' . || echo "GenericContainer(redis) 호출 미발견"
rg -n 'EmbeddedRedis' -g '*.java' -g '*.kt' . || echo "EmbeddedRedis 사용 미발견"

Length of output: 1075


CI 환경에 Redis 서비스 추가 또는 Testcontainers/Embedded Redis 설정 필요

.github/workflows에 Redis 서비스 정의가 없고, 테스트 코드에도 Testcontainers/Embedded Redis 사용 로직이 없어 실제 Redis(127.0.0.1:6379)에 의존하고 있습니다. CI에서 통합/환경 테스트가 실패하지 않도록 아래 중 하나를 적용해 주세요:

  • .github/workflows/…yml 파일의 jobs.<job>.services에 Redis 서비스 추가
    services:
      redis:
        image: redis:6-alpine
        ports:
          - 6379:6379
  • 테스트 코드에 Testcontainers 또는 Embedded Redis 설정 추가
    @Testcontainers
    public class RedisIntegrationTest {
      @Container
      static GenericContainer<?> redis = new GenericContainer<>("redis:6")
          .withExposedPorts(6379);
      // ...
    }

위 조치 없이는 CI에서 테스트가 실패합니다.

🤖 Prompt for AI Agents
infra/src/main/resources/application-redis.yml around lines 8 to 17: tests are
currently configured to use a real Redis at localhost:6379 which CI does not
provide; update CI or tests so they don't rely on a host Redis — either add a
Redis service to the relevant .github/workflows/*.yml job services (define a
redis service using the official redis image and expose 6379) or modify the test
setup to start Redis via Testcontainers or an embedded Redis instance so tests
run in CI without a local Redis.

Comment on lines +15 to +17
host: localhost
port: 6379
password:
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

test 프로필에서 Redis 비밀번호가 null로 바인딩됩니다 — 빈 문자열로 명시 권장

YAML에서 password:에 값이 없으면 null로 바인딩됩니다. 일부 클라이언트/드라이버는 빈 문자열("")과 null을 다르게 취급할 수 있어, 테스트 환경에서의 혼선을 줄이려면 명시적으로 빈 문자열을 지정하는 편이 안전합니다.

적용 예시:

       host: localhost
       port: 6379
-      password:
+      password: ""
📝 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
host: localhost
port: 6379
password:
host: localhost
port: 6379
password: ""
🤖 Prompt for AI Agents
infra/src/main/resources/application-redis.yml around lines 15 to 17: 현재
`password:`가 값 없이 남아 있어 YAML 파서는 null로 바인딩하므로 테스트 프로필에서 혼동이 발생할 수 있습니다; 빈 문자열으로
명시하려면 `password:`에 빈 문자열을 할당하도록 변경해 테스트 환경에서의 null/empty 차이를 제거하세요.

"/swagger-ui/**",
"/v3/api-docs/**",
"/kakao-login.html/**",
"/favicon.ico",
Copy link
Member

Choose a reason for hiding this comment

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

favicon.ico를 열어준 이유가 궁금합니다~

Copy link
Member

@minwoo1999 minwoo1999 left a comment

Choose a reason for hiding this comment

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

이 부분은 적용하지 않았습니다. (민우님의 의견도 궁금해요!)
설정을 하면 보안상 이점이 있을 수 있지만, 이미 Actuator 포트와 경로를 환경변수로 처리했기 때문에 굳이 설정을 추가하지 않아도 될 것 같다고 판단했습니다.

만약 인증·권한 설정을 추가하면, 요청 시 토큰을 헤더에 담아야 하고, 만료일을 길게 설정하더라도 관리포인트가 늘어난다는 단점이 크게 느껴졌습니다.

-> 이부분에 대해서 동의합니다. 저희가 MVP를 빠르게 해서 출시해 내야하는 만큼 이부분은 trade off를 생각해서 인증없이 진행해도 좋아보입니다 고생하셨습니다

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@move-hoon move-hoon merged commit a6b0ef2 into develop Aug 19, 2025
1 of 2 checks passed
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.

[BOOK-277/feat] Spring Actuator 보안 강화 및 Prometheus 설정 추가

3 participants