-
Notifications
You must be signed in to change notification settings - Fork 0
[CCI-80] Sentry 모니터링 시스템 구축 & 환경변수 비밀값 방식 적용 & 프론트엔드 CORS 설정 #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- application.yml 하나에 몰려있던 비밀값을 제거 - 환경별 profile 분리로 관리 용이성 확보 - 비밀값은 .env 기반으로 관리하도록 변경
WalkthroughUpdates CI/CD to manage environment via a remote .env file and docker --env-file, adjusts Dockerfile ordering/timezone, integrates Sentry and dotenv in Gradle, modifies CORS origins, replaces a Lombok constructor with an explicit one, updates .gitignore, and adds multiple Spring Boot profile-based YAML configs. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as GitHub Actions
participant VM as Prod Server
participant Docker as Docker Engine
Dev->>VM: SSH: mkdir -p /home/ubuntu/interview-be
Dev->>VM: Write /home/ubuntu/interview-be/.env (from secrets), chmod 600
Dev->>Docker: docker pull <image>
Dev->>Docker: docker stop rm <container> (if running)
Dev->>Docker: docker run --env-file /home/ubuntu/interview-be/.env <image>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
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. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🔭 Outside diff range comments (2)
.github/workflows/github-actions.yml (2)
55-59: Fail fast on remote errors: enable script_stopIf any remote command fails, the step should stop immediately rather than continuing to subsequent commands that may assume prior success.
Add
script_stop: true:with: host: ${{ secrets.HOST_PROD }} # EC2 퍼블릭 IPv4 DNS username: ubuntu key: ${{ secrets.PRIVATE_KEY }} + script_stop: true envs: GITHUB_SHA
42-47: Pin image by commit SHA to avoid “latest” drift and race conditionsTagging and deploying by
${{ github.sha }}ensures the same image that was built is the one deployed. You already passGITHUB_SHAto the SSH step.- name: Docker build & push to prod if: contains(github.ref, 'dev') run: | docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} - docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/interview-be-service . - docker push ${{ secrets.DOCKER_USERNAME }}/interview-be-service + docker build -f Dockerfile -t ${{ secrets.DOCKER_USERNAME }}/interview-be-service:${{ github.sha }} . + docker push ${{ secrets.DOCKER_USERNAME }}/interview-be-service:${{ github.sha }}- sudo docker pull ${{ secrets.DOCKER_USERNAME }}/interview-be-service # 최신 이미지 pull - sudo docker run -d --name interview-be-app -p 8080:8080 --env-file /home/ubuntu/interview-be/.env ${{ secrets.DOCKER_USERNAME }}/interview-be-service # 환경변수 주입하여 컨테이너 실행 + sudo docker pull ${{ secrets.DOCKER_USERNAME }}/interview-be-service:${GITHUB_SHA} # 해당 커밋 이미지 pull + sudo docker run -d --name interview-be-app -p 8080:8080 --restart unless-stopped --env-file /home/ubuntu/interview-be/.env ${{ secrets.DOCKER_USERNAME }}/interview-be-service:${GITHUB_SHA} # 환경변수 주입하여 컨테이너 실행Also applies to: 72-74
🧹 Nitpick comments (15)
src/main/java/cloudcomputinginha/demo/apiPayload/exception/GeneralException.java (1)
11-14: Add null-safety in constructor to avoid potential NPEs when code or reason is nullGuard against null
codeandcode.getReason()while building the message. Keeps thesuper(...)call first, as required by Java.Apply this diff:
public GeneralException(BaseErrorCode code) { - super("[" + code.getReason().getCode() + "] " + code.getReason().getMessage()); // 에러 메시지 전달 - this.code = code; + super("[" + + java.util.Objects.requireNonNull(code, "BaseErrorCode must not be null") + .getReason() + .getCode() + + "] " + + java.util.Objects.requireNonNull(code.getReason(), "ErrorReason must not be null") + .getMessage()); // 에러 메시지 전달 + this.code = code; }Optional follow-ups (no need to block this PR):
- Consider making the
codefieldfinalto enforce immutability.- Consider adding an overload to capture a cause:
public GeneralException(BaseErrorCode code, Throwable cause) { super("[" + code.getReason().getCode() + "] " + code.getReason().getMessage(), cause); this.code = code; }.gitignore (1)
39-45: Ignore common .env variants too.Add patterns for per-environment and editor-created env files (e.g., .env.local, .env.prod, .envrc) to prevent accidental commits.
- .env + .env + .env.* + .envrcConfirm that your CI/CD only relies on --env-file with a known filename to avoid unexpected matches.
src/main/resources/application.yml (1)
12-12: Add newline at end of file.Fixes the YAML linter warning.
src/main/resources/application-jwt.yml (1)
1-2: Add EOF newline to application-jwt.ymlThe JWT property binding is already correct—
JwtProvider.javauses@Value("${jwt.secret}")to load this value.• src/main/resources/application-jwt.yml: please add a newline at the end of the file to satisfy linters.
src/main/java/cloudcomputinginha/demo/config/auth/SecurityConfig.java (2)
35-42: Include apex domain in CORS allowlist (avoid FE CORS issues).Only www is allowed. If the FE serves from https://injob.store (apex), requests will be blocked by CORS.
Apply this small addition:
configuration.setAllowedOrigins(List.of( "http://localhost:8080", "http://localhost:3000", "http://127.0.0.1:5500", "https://www.injob.store", + "https://injob.store", domainProperties.getAi(), domainProperties.getBackend() ));If the FE might use multiple subdomains, consider using allowedOriginPatterns with explicit patterns instead.
35-42: Optional: avoid hardcoding and null-safety for dynamic origins.
- Hardcoding injob.store makes future domain changes harder; consider moving FE domain(s) into DomainProperties/application-domain.yml alongside backend/AI.
- If any of the dynamic origins are null, setAllowedOrigins will include null entries. Filter them out for safety.
One way (requires two imports):
- configuration.setAllowedOrigins(List.of( - "http://localhost:8080", - "http://localhost:3000", - "http://127.0.0.1:5500", - "https://www.injob.store", - domainProperties.getAi(), - domainProperties.getBackend() - )); + configuration.setAllowedOrigins( + java.util.stream.Stream.of( + "http://localhost:8080", + "http://localhost:3000", + "http://127.0.0.1:5500", + "https://www.injob.store", + "https://injob.store", + domainProperties.getAi(), + domainProperties.getBackend() + ).filter(java.util.Objects::nonNull).toList() + );Additional imports needed outside this hunk:
import java.util.Objects; import java.util.stream.Stream;Dockerfile (1)
2-2: Use--no-cachewhen installing tzdata and set TZ file (smaller, reproducible image).Avoids persisting apk indexes and makes timezone explicit for tooling that reads
/etc/timezone.-RUN apk add tzdata && ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime +RUN apk add --no-cache tzdata \ + && ln -snf /usr/share/zoneinfo/Asia/Seoul /etc/localtime \ + && echo "Asia/Seoul" > /etc/timezonebuild.gradle (1)
84-89: Scope dotenv to development only (avoid shipping it to prod images unless required).If Docker/CI provide envs via
--env-file/secrets, you don’t need dotenv on prod. Keep it for local dev.- // 환경변수(.env) 파일 관리 - implementation 'me.paulschwarz:spring-dotenv:4.0.0' + // 환경변수(.env) 파일 관리 (개발 환경 전용) + developmentOnly 'me.paulschwarz:spring-dotenv:4.0.0'If you don’t have it yet, declare the configuration (Boot adds it by default, but if missing add):
configurations { developmentOnly }.github/workflows/github-actions.yml (3)
63-66: Reduce heredoc delimiter collision riskIf
${{ secrets.ENV_FILE }}ever contains a line with justEOF, the heredoc will terminate prematurely. Use a less likely delimiter.- cat > .env <<'EOF' # 멀티라인 환경변수 입력으로 사용 + cat > .env <<'ENVEOF' # 멀티라인 환경변수 입력으로 사용 ${{ secrets.ENV_FILE }} - EOF + ENVEOF
60-67: Double-check secret exposure in logs; consider scp alternativeMultiline secrets are generally masked, but heredoc scripts can be echoed in logs depending on action behavior. If you want to minimize any risk, consider using appleboy/scp-action to transfer a generated .env file instead of embedding the secret into the script, or store a base64-encoded secret and decode on the remote.
I can provide an scp-based variant of this step if you want to switch. Let me know.
Also applies to: 72-74
67-67: Fix YAML trailing spaces flagged by linterTrailing spaces cause YAML lint errors on Lines 67 and 71.
- + @@ - +Also applies to: 71-71
src/main/resources/application-prod.yml (4)
36-40: Metrics config key likely ineffectiveSpring Boot expects flat keys like
management.metrics.enable.<meter>(e.g.,management.metrics.enable.jvm=false). The nestedenable: processor: enabled: falseshape won’t bind, andprocessorisn’t a standard meter id.If your goal is to disable process-related meters, use:
- Spring Boot 3.x example:
- management.metrics.enable.jvm: false
- management.metrics.enable.process: false
- management.metrics.enable.system: false
Otherwise, remove this block to avoid confusion. I can adjust to the exact meters you want disabled if you confirm your intent.
23-25: Avoid hbm2ddl.auto=update in productionAutomatic schema updates in prod can lead to unintended changes/data loss. Prefer managed migrations (Flyway/Liquibase) and set
none(Boot 3) or remove this property.- hbm2ddl: - auto: update + # hbm2ddl: + # auto: none # prefer managed migrations in production
27-29: Quartz schema initialization “always” in prod
initialize-schema: alwaysattempts schema creation on every startup. After the schema is created, considerneverto reduce startup work and log noise.- jdbc: - initialize-schema: always + jdbc: + initialize-schema: never
3-6: Minor: review JDBC URL flags
allowPublicKeyRetrieval=trueis typically used when not using SSL. WithuseSSL=true, it’s usually unnecessary. Not harmful, but you can simplify if not needed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
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.
📒 Files selected for processing (13)
.github/workflows/github-actions.yml(1 hunks).gitignore(1 hunks)Dockerfile(1 hunks)build.gradle(2 hunks)src/main/java/cloudcomputinginha/demo/apiPayload/exception/GeneralException.java(1 hunks)src/main/java/cloudcomputinginha/demo/config/auth/SecurityConfig.java(1 hunks)src/main/resources/application-aws.yml(1 hunks)src/main/resources/application-domain.yml(1 hunks)src/main/resources/application-jwt.yml(1 hunks)src/main/resources/application-oauth2.yml(1 hunks)src/main/resources/application-prod.yml(1 hunks)src/main/resources/application-sentry.yml(1 hunks)src/main/resources/application.yml(1 hunks)
🧰 Additional context used
🪛 YAMLlint (1.37.1)
src/main/resources/application-oauth2.yml
[error] 14-14: no new line character at the end of file
(new-line-at-end-of-file)
src/main/resources/application-domain.yml
[error] 3-3: no new line character at the end of file
(new-line-at-end-of-file)
src/main/resources/application-sentry.yml
[error] 7-7: no new line character at the end of file
(new-line-at-end-of-file)
src/main/resources/application.yml
[error] 12-12: no new line character at the end of file
(new-line-at-end-of-file)
.github/workflows/github-actions.yml
[error] 67-67: trailing spaces
(trailing-spaces)
[error] 71-71: trailing spaces
(trailing-spaces)
src/main/resources/application-aws.yml
[error] 6-6: no new line character at the end of file
(new-line-at-end-of-file)
src/main/resources/application-jwt.yml
[error] 2-2: no new line character at the end of file
(new-line-at-end-of-file)
🔇 Additional comments (8)
src/main/java/cloudcomputinginha/demo/apiPayload/exception/GeneralException.java (1)
20-22: Whitespace-only change — OKNo functional impact. Method remains consistent with existing API.
src/main/resources/application-sentry.yml (1)
1-7: Sane defaults; DSN/server name via env look good.Using env placeholders for DSN and server-name aligns with the new .env-driven deployment. No issues there.
src/main/resources/application.yml (2)
11-12: Forward headers strategy LGTM.FRAMEWORK is the right choice behind reverse proxies in Spring Boot 3+.
1-10: Configure ‘prod’ as a profile group instead of including it by defaultIncluding
prodinspring.profiles.includewill merge production settings into every run (local, dev, tests), risking accidental connections to live databases or services. Instead, define a profile group so that activatingprodbrings in the other profiles, but they don’t load on their own:src/main/resources/application.yml
-spring: - profiles: - include: - - prod - - jwt - - oauth2 - - aws - - domain - - sentry +spring: + profiles: + group: + prod: + - jwt + - oauth2 + - aws + - domain + - sentry• Ensure you only set
SPRING_PROFILES_ACTIVE=prod(or-Dspring.profiles.active=prod) in your production environment.
• Verify there are no other YAML/property files (e.g.application-dev.yml) or CI/local scripts that enableprodby default.
• Remove any hard-codedprodactivations from test or launcher scripts.src/main/resources/application-domain.yml (1)
1-3: Minor YAML readability and CORS origin sanity check
- Moved inline comment to its own line for clarity:
- domain: #도메인 정보 URL 생성, CORS 설정, FeignClient 등에 사용할 예정 + # 도메인 정보 URL 생성, CORS 설정, FeignClient 등에 사용할 예정 + domain: backend: ${BACKEND_URL} ai: ${AI_URL}
Ensure BACKEND_URL and AI_URL are exact origins (scheme + host + optional port), with no trailing slash, to satisfy Spring’s CORS origin matching.
Add a newline at EOF.
Note: The DomainProperties class (src/main/java/cloudcomputinginha/demo/config/properties/DomainProperties.java) is annotated with
@component and @ConfigurationProperties(prefix = "domain"), so it’s already registered and bound—no extra @EnableConfigurationProperties needed.src/main/resources/application-aws.yml (1)
1-6: cloud.aws properties are correctly bound and in use
CloudPropertiesis annotated with@ConfigurationProperties(prefix = "cloud.aws")and picks upauth,s3.bucket, ands3.region.S3ConfigwirescloudProperties.getS3().getRegion()into bothS3ClientandS3Presigner.ResumeS3ServiceandS3UrlValidatorboth callcloudProperties.getS3().getBucket()(and use it inPutObjectRequest.builder().bucket(...)and URL generation).Nitpicks:
- The
authproperty is currently declared but not consumed—either implement its use for credential selection or remove it.- Add a trailing newline to
src/main/resources/application-aws.ymlto satisfy linters.src/main/resources/application-oauth2.yml (2)
9-10: Guard against double slashes in callback URL.If BACKEND_URL ends with “/” or GOOGLE_CALLBACK_ENDPOINT begins with “/”, you’ll end up with a “//” in the URL. Prefer one source of the slash.
If your env defines GOOGLE_CALLBACK_ENDPOINT without a leading slash (recommended), apply:
- url: ${BACKEND_URL}/${GOOGLE_CALLBACK_ENDPOINT} + url: ${BACKEND_URL}${GOOGLE_CALLBACK_ENDPOINT}Alternatively, ensure GOOGLE_CALLBACK_ENDPOINT never starts with “/”.
12-14: Ensure allowed-redirect-uris format matches the binder type.If the bound property is a
List<String>, Spring Boot will split comma-separated values. Confirm ALLOWED_REDIRECT_URIS follows “uri1,uri2,uri3” with no spaces, and that code expects a list.Want me to scan for the properties class that reads these (e.g.,
frontend.allowed-redirect-uris) to confirm the expected type and delimiter?
- yml key 오타 수정
✨ 작업 개요
✅ 작업 내용
📌 참고 사항(선택)
💬리뷰 요구사항(선택)
🔗 관련 이슈
CCI-80
Summary by CodeRabbit
New Features
Chores