Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 6 minutes and 39 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
WalkthroughAPI 버전 관리 시스템을 도입하여 모든 컨트롤러를 Changes
Sequence DiagramsequenceDiagram
participant Client as 클라이언트
participant DispatcherServlet as DispatcherServlet
participant APIVersionConfig as APIVersionConfig<br/>(PathMatchConfigurer)
participant Controller as 버전 관리 컨트롤러<br/>(`@Api1Version`)
Client->>DispatcherServlet: GET /api/v1/books
DispatcherServlet->>APIVersionConfig: 경로 매칭 검사
APIVersionConfig->>APIVersionConfig: HandlerTypePredicate로<br/>@Api1Version 확인
APIVersionConfig->>APIVersionConfig: /api/v1 접두어 제거<br/>실제 경로: /books
APIVersionConfig->>Controller: /books로 라우팅
Controller->>Controller: 비즈니스 로직 처리
Controller-->>DispatcherServlet: 응답 반환
DispatcherServlet-->>Client: HTTP 200 + JSON
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~45분 Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 4❌ Failed checks (3 warnings, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/app/nook/user/dev/MockUserInitializer.java (1)
29-31:⚠️ Potential issue | 🟠 Major관리자 목업 계정이 일반 사용자 권한으로 생성됩니다.
Line 29-31에서
DEV_ADMIN계정을 만들지만, Line 51에서 role을UserRole.USER로 고정해admin@test.com도 USER 권한으로 저장됩니다. 관리자 시나리오(권한 테스트/운영 점검) 검증이 깨질 수 있습니다.createIfNotExists에 role 파라미터를 추가해 계정별로 명시하세요.수정 제안 diff
@@ createIfNotExists( "dev@test.com", - "DEV_USER" + "DEV_USER", + UserRole.USER ); createIfNotExists( "admin@test.com", - "DEV_ADMIN" + "DEV_ADMIN", + UserRole.ADMIN ); @@ private void createIfNotExists( String email, - String nickname + String nickname, + UserRole role ) { @@ User user = User.builder() .email(email) .nickName(nickname) .provider("DEV") .providerId("DEV_" + email) - .role(UserRole.USER) + .role(role) .build();Also applies to: 46-52
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/main/java/app/nook/user/dev/MockUserInitializer.java` around lines 29 - 31, The admin mock account is being created but later forced to UserRole.USER; update the MockUserInitializer to accept and propagate a role parameter to createIfNotExists and use it when saving the user instead of hardcoding UserRole.USER. Specifically, add a role argument to the createIfNotExists method (and its callers), ensure the method uses that role when constructing/persisting the account (instead of UserRole.USER), and call it with UserRole.ADMIN for "admin@test.com" while keeping other calls using UserRole.USER as appropriate; update any references to the method signature (e.g., MockUserInitializer.createIfNotExists and its invocations) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/deploy-cicd.yml:
- Around line 116-122: 현재 워크플로우가
src/main/resources/application-secret.properties를 만들어서 ./gradlew clean build로
JAR에 비밀을 패키징하고 있으며(application.yml이
optional:classpath:application-secret.properties로 로드함), 이 파일 생성을 제거하고 비밀을 런타임에
주입하도록 변경하세요: .github/workflows/deploy-cicd.yml에서 application-secret.properties
생성 스텝을 삭제하고 대신 컨테이너 런타임(ECS task definition / Kubernetes secret / Docker run -v
또는 엔트리포인트에서 읽는 환경변수)으로 주입하도록 구성하며, 필요하면 애플리케이션이 application-secret.properties 대신
환경변수나 외부 파일 위치(SPRING_CONFIG_LOCATION 또는 spring.config.import 등)를 사용하도록 코드/
Dockerfile과 설정을 업데이트하세요 so the ./gradlew clean build step no longer bakes
secrets into the JAR.
- Around line 174-178: Replace the runtime git pull with a deterministic
checkout to the exact triggered commit: instead of running "git pull origin
develop-demo" use a fetch+reset to the workflow's SHA (referencing github.sha /
GITHUB_SHA) so the server working tree matches the image build commit exactly;
update the deployment step that currently calls git pull to fetch the specific
commit (e.g., fetch origin <SHA> and git reset --hard <SHA> or use
actions/checkout equivalent) and then continue to run chmod +x scripts/deploy.sh
and ./scripts/deploy.sh "$IMAGE".
- Line 160: Replace the mutable `@master` action refs with immutable commit SHAs:
locate the two uses entries referencing appleboy/ssh-action@master and
Ilshidur/action-discord@master and change each to the full 40-character commit
SHA for the intended release (or a released tag plus the matching SHA), leaving
a comment next to the entry documenting the original tag/version and the SHA you
pinned; ensure the new uses values are the exact commit SHAs so the SSH key and
Discord webhook steps are immutable and cannot be changed by branch updates.
- Around line 55-59: The JaCoCo action step named "JaCoCo PR Report" is passing
the binary exec file via the paths input; change it to point at the generated
JaCoCo XML report instead (the XML produced by jacocoTestReport). Update the
paths value for the madrapps/jacoco-report step (the step with name "JaCoCo PR
Report" and input key `paths`) to the XML report path produced by your Gradle
task (e.g., the jacocoTestReport XML under
build/reports/jacoco/.../jacocoTestReport.xml) so the action can parse and post
PR coverage correctly.
In `@Dockerfile`:
- Line 11: The Dockerfile's COPY line "COPY build/libs/*.jar app.jar" fails when
multiple JARs exist; update the build and Dockerfile so only one artifact is
copied: configure Gradle to produce a single expected filename (e.g., set
bootJar.enabled = true and disable plain jar or set
archiveBaseName/archiveClassifier) or explicitly reference the exact jar name in
the Dockerfile COPY, and replace the glob COPY with the explicit artifact
filename; ensure the changes reference the Dockerfile COPY line and the Gradle
tasks (bootJar, jar) so CI builds a single predictable JAR and the Docker COPY
succeeds.
---
Outside diff comments:
In `@src/main/java/app/nook/user/dev/MockUserInitializer.java`:
- Around line 29-31: The admin mock account is being created but later forced to
UserRole.USER; update the MockUserInitializer to accept and propagate a role
parameter to createIfNotExists and use it when saving the user instead of
hardcoding UserRole.USER. Specifically, add a role argument to the
createIfNotExists method (and its callers), ensure the method uses that role
when constructing/persisting the account (instead of UserRole.USER), and call it
with UserRole.ADMIN for "admin@test.com" while keeping other calls using
UserRole.USER as appropriate; update any references to the method signature
(e.g., MockUserInitializer.createIfNotExists and its invocations) accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 28947c3d-ff74-43b4-b5f8-9783a7625047
📒 Files selected for processing (32)
.github/workflows/deploy-cicd.ymlDockerfilebuild.gradlesrc/main/java/app/nook/api/APIVersionConfig.javasrc/main/java/app/nook/api/Api1Version.javasrc/main/java/app/nook/book/controller/BookController.javasrc/main/java/app/nook/book/controller/BookSearchController.javasrc/main/java/app/nook/book/controller/CategoryController.javasrc/main/java/app/nook/focus/controller/FocusController.javasrc/main/java/app/nook/global/config/WebSecurityConfig.javasrc/main/java/app/nook/library/controller/LibraryController.javasrc/main/java/app/nook/library/controller/LibraryStatsController.javasrc/main/java/app/nook/r2/controller/ImageUploadController.javasrc/main/java/app/nook/record/controller/RecordController.javasrc/main/java/app/nook/timeline/controller/TimelineController.javasrc/main/java/app/nook/user/controller/AuthController.javasrc/main/java/app/nook/user/controller/OnboardingController.javasrc/main/java/app/nook/user/dev/MockUserInitializer.javasrc/main/resources/application.ymlsrc/test/java/app/nook/controller/book/BookControllerTest.javasrc/test/java/app/nook/controller/book/BookSearchControllerTest.javasrc/test/java/app/nook/controller/book/CategoryControllerTest.javasrc/test/java/app/nook/controller/focus/FocusControllerTest.javasrc/test/java/app/nook/controller/focus/FocusThemeControllerTest.javasrc/test/java/app/nook/controller/library/LibraryControllerTest.javasrc/test/java/app/nook/controller/library/LibraryStatsControllerTest.javasrc/test/java/app/nook/controller/r2/ImageUploadControllerTest.javasrc/test/java/app/nook/controller/record/RecordControllerTest.javasrc/test/java/app/nook/controller/timeline/TimelineControllerTest.javasrc/test/java/app/nook/controller/user/AuthControllerTest.javasrc/test/java/app/nook/controller/user/OnboardingControllerTest.javasrc/test/java/app/nook/global/common/TestSecurityConfig.java
| - name: application-secret.properties 생성 | ||
| run: | | ||
| mkdir -p ./src/main/resources | ||
| echo "${{ secrets.APPLICATION_SECRET_PROPERTIES_DEV }}" > ./src/main/resources/application-secret.properties | ||
|
|
||
| - name: Docker 이미지용 JAR + RestDocs 생성 | ||
| run: ./gradlew clean build |
There was a problem hiding this comment.
비밀값을 빌드 산출물에 내장하고 있습니다.
여기서 src/main/resources/application-secret.properties를 만든 뒤 바로 ./gradlew clean build를 돌리면 그 파일이 JAR 클래스패스 리소스로 패키징됩니다. 현재 src/main/resources/application.yml 1-3행도 이를 optional:classpath:application-secret.properties로 읽게 되어 있어서, 결과적으로 dev 비밀값이 ECR 이미지에 고정됩니다. 런타임 주입으로 바꾸지 않으면 비밀값 회전과 이미지 접근 권한 분리가 어려워집니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/deploy-cicd.yml around lines 116 - 122, 현재 워크플로우가
src/main/resources/application-secret.properties를 만들어서 ./gradlew clean build로
JAR에 비밀을 패키징하고 있으며(application.yml이
optional:classpath:application-secret.properties로 로드함), 이 파일 생성을 제거하고 비밀을 런타임에
주입하도록 변경하세요: .github/workflows/deploy-cicd.yml에서 application-secret.properties
생성 스텝을 삭제하고 대신 컨테이너 런타임(ECS task definition / Kubernetes secret / Docker run -v
또는 엔트리포인트에서 읽는 환경변수)으로 주입하도록 구성하며, 필요하면 애플리케이션이 application-secret.properties 대신
환경변수나 외부 파일 위치(SPRING_CONFIG_LOCATION 또는 spring.config.import 등)를 사용하도록 코드/
Dockerfile과 설정을 업데이트하세요 so the ./gradlew clean build step no longer bakes
secrets into the JAR.
|
|
||
| steps: | ||
| - name: Dev 서버 배포 | ||
| uses: appleboy/ssh-action@master |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's check the workflow file exists and view the relevant lines
wc -l .github/workflows/deploy-cicd.ymlRepository: UMC-NOOK/Server
Length of output: 96
🏁 Script executed:
# View lines around 160 and 195 to confirm the `@master` references
sed -n '150,170p' .github/workflows/deploy-cicd.yml
sed -n '185,205p' .github/workflows/deploy-cicd.ymlRepository: UMC-NOOK/Server
Length of output: 1074
🏁 Script executed:
# Get full context of the workflow file to understand the jobs and their purposes
cat -n .github/workflows/deploy-cicd.ymlRepository: UMC-NOOK/Server
Length of output: 7089
🌐 Web query:
GitHub Actions security best practices pinning actions to commit SHA
💡 Result:
Why pin GitHub Actions to a commit SHA?
Using uses: owner/repo@v1 (or @main) is risky because tags/branches can move (intentionally or after a compromise), causing your workflow to run different code than you reviewed. GitHub’s guidance is to pin to a full-length commit SHA to make the reference immutable. (docs.github.com)
Recommended pattern (with human-readable context)
steps:
- uses: actions/checkout@<FULL_LENGTH_COMMIT_SHA> # v4.2.2This keeps the workflow locked to the exact commit, while the comment documents the intended release/tag. (docs.github.com)
Enforce SHA pinning (org/enterprise governance)
GitHub Actions policy can require actions/reusable workflows to be pinned to a full commit SHA; workflows that aren’t pinned can be blocked from running. (github.blog)
Handling the “but we need updates” tradeoff
Pinning means you must deliberately update SHAs. Common approaches:
- Use a tool/bot to open PRs updating pinned SHAs (e.g., “pin-github-action” style tooling). (github.com)
- Add a CI check that fails if any
uses:isn’t SHA-pinned (helps prevent regressions). (github.com)
Prefer immutable releases (if you publish actions)
If you maintain actions, GitHub recommends release practices (including immutable releases/tags) to make what consumers depend on harder to change unexpectedly. (docs.github.com)
Citations:
- 1: https://docs.github.com/github-ae%40latest/actions/security-guides/security-hardening-for-github-actions?utm_source=openai
- 2: https://docs.github.com/github-ae%40latest/actions/security-guides/security-hardening-for-github-actions?utm_source=openai
- 3: https://github.blog/changelog/2025-08-15-github-actions-policy-now-supports-blocking-and-sha-pinning-actions/?utm_source=openai
- 4: https://github.com/mheap/pin-github-action?utm_source=openai
- 5: https://github.com/marketplace/actions/ensure-sha-pinned-actions?utm_source=openai
- 6: https://docs.github.com/en/actions/how-tos/create-and-publish-actions/using-immutable-releases-and-tags-to-manage-your-actions-releases?utm_source=openai
@master 액션 참조는 배포 워크플로에서 보안 위험입니다.
appleboy/ssh-action@master (160줄)와 Ilshidur/action-discord@master (195줄)는 @master 참조를 사용하고 있습니다. GitHub의 공식 보안 가이드에 따르면 브랜치나 태그는 의도적으로 또는 손상 후 변경될 수 있으므로, 액션을 전체 길이의 커밋 SHA로 고정하는 것이 가장 안전한 방식입니다. SSH 개인 키와 Discord webhook secret을 다루는 이 두 액션은 반드시 immutable reference(커밋 SHA)로 변경해야 합니다. 커밋 SHA와 함께 의도한 버전/태그를 주석으로 남길 수 있습니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/deploy-cicd.yml at line 160, Replace the mutable `@master`
action refs with immutable commit SHAs: locate the two uses entries referencing
appleboy/ssh-action@master and Ilshidur/action-discord@master and change each to
the full 40-character commit SHA for the intended release (or a released tag
plus the matching SHA), leaving a comment next to the entry documenting the
original tag/version and the SHA you pinned; ensure the new uses values are the
exact commit SHAs so the SSH key and Discord webhook steps are immutable and
cannot be changed by branch updates.
| cd ~/app | ||
| git pull origin develop-demo | ||
|
|
||
| chmod +x scripts/deploy.sh | ||
| ./scripts/deploy.sh "$IMAGE" |
There was a problem hiding this comment.
서버에서 git pull하지 말고 트리거된 SHA로 고정하세요.
이미지는 docker-dev job에서 특정 커밋 기준으로 빌드했는데, 배포 시점에 서버에서 다시 develop-demo HEAD를 pull 하면 그 사이 들어온 더 새로운 스크립트/compose 파일과 이전 이미지 태그가 섞일 수 있습니다. 재현성과 롤백이 바로 깨지는 지점이라, 최소한 ${{ github.sha }}로 fetch/reset 해서 동일 커밋만 배포하게 고정하는 편이 낫습니다.
예시 수정
- cd ~/app
- git pull origin develop-demo
+ cd ~/app
+ git fetch origin develop-demo --depth=1
+ git checkout develop-demo
+ git reset --hard ${{ github.sha }}
+ git clean -fd📝 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.
| cd ~/app | |
| git pull origin develop-demo | |
| chmod +x scripts/deploy.sh | |
| ./scripts/deploy.sh "$IMAGE" | |
| cd ~/app | |
| git fetch origin develop-demo --depth=1 | |
| git checkout develop-demo | |
| git reset --hard ${{ github.sha }} | |
| git clean -fd | |
| chmod +x scripts/deploy.sh | |
| ./scripts/deploy.sh "$IMAGE" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/deploy-cicd.yml around lines 174 - 178, Replace the
runtime git pull with a deterministic checkout to the exact triggered commit:
instead of running "git pull origin develop-demo" use a fetch+reset to the
workflow's SHA (referencing github.sha / GITHUB_SHA) so the server working tree
matches the image build commit exactly; update the deployment step that
currently calls git pull to fetch the specific commit (e.g., fetch origin <SHA>
and git reset --hard <SHA> or use actions/checkout equivalent) and then continue
to run chmod +x scripts/deploy.sh and ./scripts/deploy.sh "$IMAGE".
| apt-get clean | ||
|
|
||
| COPY --from=build /app/build/libs/*.jar app.jar | ||
| COPY build/libs/*.jar app.jar |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -e
# 1) Dockerfile의 와일드카드 COPY 사용 여부 확인
rg -n 'COPY\s+build/libs/\*\.jar\s+app\.jar|COPY\s+build/libs/app\.jar\s+app\.jar' Dockerfile
# 2) Gradle에서 bootJar 이름 고정 / plain jar 비활성화 여부 확인
rg -n 'tasks\.named\("bootJar"\)|archiveFileName\s*=\s*"app\.jar"|tasks\.named\("jar"\)|enabled\s*=\s*false' build.gradleRepository: UMC-NOOK/Server
Length of output: 91
🏁 Script executed:
# build.gradle 파일 찾기 및 내용 확인
fd -type f -name 'build.gradle*'Repository: UMC-NOOK/Server
Length of output: 229
🏁 Script executed:
# build.gradle 내용 조회 (jar 관련 설정 포함)
cat build.gradleRepository: UMC-NOOK/Server
Length of output: 5243
COPY build/libs/*.jar app.jar는 다중 JAR 매칭 시 Docker 빌드를 실패시킵니다.
현재 build.gradle에 bootJar 또는 jar 태스크 설정이 없으므로, Spring Boot 기본 동작에 따라 build/libs/ 디렉토리에 plain JAR과 boot JAR 2개가 생성됩니다. COPY 명령어가 여러 파일을 단일 파일 목적지(app.jar)로 복사하려 하면 Docker 빌드가 실패합니다. 산출물을 명시적으로 관리하고 단일 파일만 복사하도록 변경해야 합니다.
🔧 제안 수정안
# Dockerfile
-COPY build/libs/*.jar app.jar
+COPY build/libs/app.jar app.jar# build.gradle (맨 아래에 추가)
+tasks.named("bootJar") {
+ archiveFileName = "app.jar"
+}
+
+tasks.named("jar") {
+ enabled = false
+}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Dockerfile` at line 11, The Dockerfile's COPY line "COPY build/libs/*.jar
app.jar" fails when multiple JARs exist; update the build and Dockerfile so only
one artifact is copied: configure Gradle to produce a single expected filename
(e.g., set bootJar.enabled = true and disable plain jar or set
archiveBaseName/archiveClassifier) or explicitly reference the exact jar name in
the Dockerfile COPY, and replace the glob COPY with the explicit artifact
filename; ensure the changes reference the Dockerfile COPY line and the Gradle
tasks (bootJar, jar) so CI builds a single predictable JAR and the Docker COPY
succeeds.
|
📄 작업 내용 요약
CICD 배포 파이프라인 설정
API V1으로 일괄수정
TODO
📎 Issue 번호
✅ 작업 목록
📝 기타 참고사항
Summary by CodeRabbit
릴리스 노트
New Features
/api/v1접두사 사용Chores
Tests