Skip to content

Conversation

@kaswhy
Copy link
Member

@kaswhy kaswhy commented Aug 23, 2025

📌 연관된 이슈

✨ 작업 내용

  • dev, prod 환경 분리

💬 리뷰 요구사항(선택)

Summary by CodeRabbit

  • 신기능
    • 개발용 CD 워크플로우 추가: main 푸시 시 개발용 이미지 빌드·S3 업로드·CodeDeploy 배포 자동화.
    • 개발용 Docker 구성, 배포 스크립트, 개발 프로필 애플리케이션 설정 및 CodeDeploy 앱스펙 추가.
    • 운영·개발 환경에 Dozzle 서비스(컨테이너 모니터링) 추가.
  • 작업(Chores)
    • 프로덕션 워크플로우 이름/액션 업그레이드 및 프로덕션 전용 아티팩트·비밀 패키징 정리.
    • 프로덕션 배포 스크립트에 정적분석 예외 주석 추가(동작 유지).
    • Flyway 프로덕션 설정에서 baseline-on-migrate 비활성화.

@kaswhy kaswhy self-assigned this Aug 23, 2025
@kaswhy kaswhy added the enhancement New feature or request label Aug 23, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 23, 2025

Walkthrough

개발/운영 환경을 분리하기 위해 Dev 전용 CI/CD 워크플로우와 배포 아티팩트(Compose, AppSpec, 스크립트, Spring 설정)를 추가하고, Prod 워크플로우/아티팩트 명칭과 패키징을 운영 전용으로 정리했습니다. 또한 Prod Flyway 설정(baseline-on-migrate)을 false로 변경했습니다.

Changes

Cohort / File(s) Summary
CI/CD - Dev 파이프라인 추가
.github/workflows/deploy-dev.yml
main 푸시 시 Dev 도커 이미지 빌드·푸시, dev 아티팩트 복사, .env 생성·압축, S3 업로드, CodeDeploy 배포 생성
CI/CD - Prod 워크플로우 정리
.github/workflows/deploy-prod.yml
워크플로우명 변경, actions/checkout@v4·docker/login-action@v3로 업그레이드, prod 전용 아티팩트 복사·패키징 및 DOZZLE 자격증명 포함
배포 아티팩트 - Dev
gdgoc/docker-compose-dev.yml, gdgoc/appspec.dev.yml, gdgoc/deploy.dev.sh
Dev용 docker-compose, CodeDeploy AppSpec, 배포 스크립트 신규 추가 (이미지명/dev 포트/환경 변수 등 설정)
배포 아티팩트 - Prod 보완
gdgoc/appspec.prod.yml, gdgoc/deploy.prod.sh, gdgoc/docker-compose-prod.yml
AppSpec AfterInstall이 deploy.prod.sh 참조로 변경, deploy.prod.sh에 ShellCheck 억제 주석 추가, prod Compose에 dozzle 서비스 추가 및 관련 env_file 구성
Spring 설정 - Dev 추가
gdgoc/src/main/resources/application-dev.yml
개발 프로파일용 Spring/JPA/Flyway/Mail/OAuth/JWT/AWS 등 환경변수 기반 설정 신규 추가
Spring 설정 - Prod 조정
gdgoc/src/main/resources/application-prod.yml
spring.flyway.baseline-on-migratetruefalse로 변경

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Dev as 개발자
  participant GH as GitHub Actions (deploy-dev)
  participant DH as Docker Hub
  participant S3 as S3
  participant CD as CodeDeploy
  participant EC2 as EC2 (Dev)
  participant DC as Docker Compose

  Dev->>GH: main에 푸시
  GH->>DH: Dev 이미지 빌드 및 푸시 (DOCKER_HUB_USERNAME/gdgoc-be-app-dev:latest)
  GH->>S3: deploy-dev.zip(.env + docker-compose-dev.yml + deploy.dev.sh + appspec.yml) 업로드
  GH->>CD: Dev 앱/그룹으로 배포 생성 (bundle: s3://.../deploy-dev.zip)
  CD->>EC2: AfterInstall -> `deploy.dev.sh` 실행
  EC2->>DH: 도커 이미지 풀
  EC2->>DC: `docker-compose --env-file .env up -d` 실행
  note right of EC2: Dev 스택 시작
Loading
sequenceDiagram
  autonumber
  participant Dev as 개발자
  participant GH as GitHub Actions (deploy-prod)
  participant DH as Docker Hub
  participant S3 as S3
  participant CD as CodeDeploy
  participant EC2 as EC2 (Prod)
  participant DC as Docker Compose

  Dev->>GH: main에 푸시
  GH->>DH: Prod 이미지 빌드 및 푸시 (DOCKER_HUB_USERNAME/gdgoc-be-app:latest)
  GH->>S3: deploy-prod.zip(.env + docker-compose-prod.yml + deploy.prod.sh + appspec.yml) 업로드
  GH->>CD: Prod 앱/그룹으로 배포 생성 (bundle: s3://.../deploy-prod.zip)
  CD->>EC2: AfterInstall -> `deploy.prod.sh` 실행
  EC2->>DH: 프로덕션 이미지 풀
  EC2->>DC: `docker-compose -f docker-compose-prod.yml --env-file .env up -d`
  note right of EC2: Prod 스택 업데이트
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Assessment against linked issues

Objective Addressed Explanation
Dev/Prod 환경 분리 및 독립 배포 파이프라인 구성 (#70)
Dev 전용 컨테이너/Compose/스크립트/설정 추가 (#70)
Prod 전용 아티팩트로 워크플로우/훅 정리 (#70)
운영 영향 최소화(환경 분리) 관련 요구 (#70)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Flyway baseline-on-migrate 변경 (gdgoc/src/main/resources/application-prod.yml) 배포 파이프라인 분리 목적과 직접적인 연관이 명확하지 않음; 데이터 마이그레이션 동작에 영향을 주는 설정 변경으로 별도 검토 필요 (라인: application-prod.yml의 spring.flyway.baseline-on-migrate).

Possibly related PRs

  • [FEAT] #178: CI 추가 #180 — 동일 파일(gdgoc/src/main/resources/application-prod.yml)의 Flyway baseline-on-migrate 설정 변경과 연관성이 높음.

Poem

"폴짝폴짝, 브랜치 사이로 나는 토끼 🐇
dev는 왼쪽 굴에, prod는 오른쪽 들에,
이미지 쌓고, 압축 싸서 S3에 던지네.
훅이 울리고 스크립트가 춤추면,
당근 같은 배포가 맛있게 익었네."

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/issue-70

🪧 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.

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

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.

@github-actions
Copy link

github-actions bot commented Aug 23, 2025

CI status
✅ Assemble 성공
✅ Test 성공

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: 10

Caution

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

⚠️ Outside diff range comments (4)
gdgoc/deploy.prod.sh (2)

23-24: Compose 파일 미지정: prod용 docker-compose가 로드되지 않음

작업 디렉터리에 docker-compose.yml이 없다면 현재 명령은 gdgoc/docker-compose-prod.yml을 사용하지 않습니다. 실제로는 아무 것도 안 올라가거나 이전 잔존 파일을 사용할 수 있습니다. 반드시 -f로 prod용 파일을 지정해 주세요.

아래처럼 수정 제안:

-# 기존 컨테이너 중지 및 삭제
-docker-compose down
+COMPOSE_FILE="gdgoc/docker-compose-prod.yml"
+# 기존 컨테이너 중지 (필요 시)
+docker-compose -f "$COMPOSE_FILE" down

그리고 하단 up도 동일 파일을 지정하세요:

-docker-compose --env-file .env up -d
+docker-compose -f "$COMPOSE_FILE" --env-file .env up -d

26-30: 운영에서 system prune/volume prune는 위험(데이터/캐시 제거)

docker system prune -afdocker volume prune -f는 불필요 리소스뿐 아니라 캐시/네트웍/라벨 없는 볼륨까지 제거합니다. 운영 데이터 손실 리스크가 있습니다. 유지보수 윈도우/백업 없는 상태에서는 사용하지 마세요.

다음과 같이 비활성화 또는 환경변수 게이트 도입을 권장:

-# 사용되지 않는 컨테이너, 이미지, 네트워크, 볼륨 정리
-docker system prune -af
-
-# 불필요한 Docker 볼륨도 정리 (옵션)
-docker volume prune -f
+# (옵션) 유지보수 윈도우에서만 실행
+if [[ "${ALLOW_PRUNE:-false}" == "true" ]]; then
+  docker system prune -af
+  docker volume prune -f
+fi
.github/workflows/deploy-prod.yml (2)

13-20: GitHub Actions 버전 업그레이드 필요 (checkout/login-action).

actionlint 기준으로 러너가 너무 오래된 액션을 사용 중입니다. actions/checkout@v4, docker/login-action@v3로 올려주세요. 최신 보안 패치/성능 개선과 함께 향후 런타임 불일치 이슈를 예방합니다.

다음과 같이 교체하세요:

-      - name: Checkout Repository
-        uses: actions/checkout@v3
+      - name: Checkout Repository
+        uses: actions/checkout@v4
...
-      - name: Log in to Docker Hub
-        uses: docker/login-action@v2
+      - name: Log in to Docker Hub
+        uses: docker/login-action@v3

22-26: 이미지 태깅 방식 개선: latest 단독 사용 지양, 불변 태그 추가.

운영 배포에서 :latest만 푸시/사용하면 롤백/재현이 어렵고 드리프트가 발생합니다. 커밋 SHA 기반의 불변 태그를 병행해 주세요.

예시:

-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest
+          GIT_SHA=$(git rev-parse --short HEAD)
+          IMAGE=${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app
+          docker build -t "$IMAGE:latest" -t "$IMAGE:${GIT_SHA}" .
+          docker push "$IMAGE:latest"
+          docker push "$IMAGE:${GIT_SHA}"

그리고 docker-compose-prod.yml이 이 태그를 참조하도록 업데이트하는 것을 권장합니다.

♻️ Duplicate comments (1)
gdgoc/deploy.prod.sh (1)

37-38: Compose up에도 파일 경로 지정 누락

위에서 제안한 COMPOSE_FILE 사용과 일관되게 up에도 -f를 지정하세요.

🧹 Nitpick comments (22)
gdgoc/src/main/resources/application-prod.yml (1)

44-47: 운영 환경에서 SQL 디버그 로깅 비권장

org.hibernate.SQL: debug는 운영에서 과도한 로그 유발과 PII 노출 리스크가 있습니다. 운영에서는 info 이하로 낮추는 것을 권장합니다.

다음과 같이 조정 제안:

 logging:
   level:
-    org.hibernate.SQL: debug
+    org.hibernate.SQL: info
     org.hibernate.type: off
gdgoc/deploy.prod.sh (4)

5-20: 도커/컴포즈 설치 로직 개선 여지

  • 스크립트가 CodeDeploy runas: root로 실행되므로 sudo는 불필요합니다.
  • 구식 docker-compose 바이너리 직접 설치 대신, 배포 표준인 compose-plugin(docker compose) 사용을 권장합니다. 바이너리 직다운로드에는 무결성/재현성 문제가 있습니다.

설치 블록 단순화 예시(우분투 기준):

-if ! [ -x "$(command -v docker-compose)" ]; then
-  echo "Docker Compose가 설치되어 있지 않습니다. 설치 중..."
-  sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
-  sudo chmod +x /usr/local/bin/docker-compose
-  echo "Docker Compose 설치 완료"
-fi
+# Compose plugin 설치 (권장)
+apt-get update && apt-get install -y docker-compose-plugin
+command -v docker compose >/dev/null || { echo "compose plugin 설치 실패"; exit 1; }

필요 시 스크립트의 docker-compose 호출을 docker compose로 치환하세요.


1-3: 기본 안전 옵션(set -Eeuo pipefail)과 cd 실패 처리 권장

현재 # shellcheck disable=SC2164로 넘어가지만, 실패 시 중단되도록 하는 것이 안전합니다.

상단에 안전 옵션과 cd 체크 추가:

-#!/bin/bash
-# shellcheck disable=SC2164
-cd /home/ubuntu/gdgoc-be-app
+#!/bin/bash
+set -Eeuo pipefail
+cd /home/ubuntu/gdgoc-be-app || { echo "작업 디렉터리 진입 실패"; exit 1; }

22-24: 다운타임 최소화 배포로 개선

downup은 가용성에 영향을 줍니다. 통상 pullup -d --remove-orphans로 무중단에 가깝게 갱신합니다(서비스 구조에 따라 다름).

예시:

-# 기존 컨테이너 중지 및 삭제
-docker-compose -f "$COMPOSE_FILE" down
+docker-compose -f "$COMPOSE_FILE" pull
+docker-compose -f "$COMPOSE_FILE" up -d --remove-orphans

15-20: 네트워크 접근(깃허브 릴리즈) 의존: 배포 실패 가능성

github.com/docker/compose/releases/latest에서 바이너리 직접 받는 로직은 일시적 실패/레이트리밋에 취약합니다. 사내 미러 또는 apt 리포지토리 사용을 권장합니다.

gdgoc/src/main/resources/application-dev.yml (2)

67-68: S3 버킷 환경변수 키 불일치

prod는 ${AWS_RESOURCE_BUCKET}, dev는 ${WS_TEST_RESOURCE_BUCKET}를 사용합니다. 키가 다르면 워크플로/시크릿 관리가 복잡해집니다. 동일 키를 환경별 값으로 분리하거나, 접미만 다른 일관 규칙(예: AWS_RESOURCE_BUCKET vs AWS_RESOURCE_BUCKET_DEV)을 권장합니다.

예시:

-      bucket: ${WS_TEST_RESOURCE_BUCKET}
+      bucket: ${AWS_RESOURCE_BUCKET}

(또는 AWS_RESOURCE_BUCKET_DEV로 명시적으로 분리하고 CI에서 주입)


1-69: 중복 설정 공통화 제안

dev/prod 모두 동일한 블록(Jackson/JPA/Mail/JWT/AWS 등)이 반복됩니다. application.yml 또는 application-common.yml로 공통 설정을 두고, 프로필별 파일에서는 차이점만 정의하면 drift와 휴먼에러를 줄일 수 있습니다.

gdgoc/appspec.prod.yml (1)

9-11: 스크립트 연결 OK. 추가 훅 고려 여지

AfterInstall에서 배포 스크립트를 실행하도록 한 연결은 적절합니다. 다만 무중단/안전성 향상을 위해 ApplicationStop(기존 버전 종료) 또는 BeforeInstall(백업/헬스체크 준비) 훅을 도입하는 것을 고려해 주세요. 또한 deploy.prod.sh 실행 권한(chmod +x)이 보장되는지 워크플로에서 확인 바랍니다.

.github/workflows/deploy-prod.yml (4)

35-55: .env 생성 로직 간소화 + 출력 최소화 (SC2129).

여러 번의 리다이렉션 대신 heredoc을 사용하면 로그 노이즈/오류 가능성을 줄일 수 있습니다. 또한 필요 최소한 값만 포함하세요.

-          echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
-          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env
-          echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
-          echo "DB_NAME=${{ secrets.DB_NAME }}" >> .env
-          echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
-          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
-          echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
-          echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
-          echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
-          echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
-          echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
-          echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
-          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
-          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
-          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
-          echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
-          echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
-          echo "GMAIL=${{secrets.GMAIL}}" >> .env
-          echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
+          cat > .env <<'EOF'
+          DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}
+          DB_HOST=${{ secrets.DB_HOST }}
+          DB_PORT=${{ secrets.DB_PORT }}
+          DB_NAME=${{ secrets.DB_NAME }}
+          DB_USERNAME=${{ secrets.DB_USERNAME }}
+          DB_PASSWORD=${{ secrets.DB_PASSWORD }}
+          GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
+          GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
+          GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}
+          GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}
+          SELF_ISSUER=${{ secrets.SELF_ISSUER }}
+          SECRET_KEY=${{ secrets.SECRET_KEY }}
+          AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          AWS_REGION=${{ secrets.AWS_REGION }}
+          AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}
+          AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}
+          GMAIL=${{ secrets.GMAIL }}
+          GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}
+          EOF

55-56: 배포 아카이브 파일명 충돌 방지.

운영도 키에 커밋 SHA 등을 포함하면 이전 아티팩트와 구분되고 캐싱 이슈를 줄일 수 있습니다.

-          zip -r deploy.zip .env docker-compose-prod.yml deploy.prod.sh appspec.prod.yml
+          GIT_SHA=$(git rev-parse --short HEAD)
+          zip -r "deploy-${GIT_SHA}.zip" .env docker-compose-prod.yml deploy.prod.sh appspec.prod.yml

이후 S3 업로드/CodeDeploy 단계에서도 동일 파일명을 사용하도록 변경 필요.


57-62: AWS 자격 증명 구성은 OIDC 기반 공식 액션 사용 권장.

aws configure로 러너 환경에 영구 설정하는 패턴 대신 aws-actions/configure-aws-credentials@v4를 사용하면 보안/감사 추적이 좋아집니다.

예:

-      - name: Configure AWS credentials
-        run: |
-          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
-          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-          aws configure set region ${{ secrets.AWS_REGION }}
+      - name: Configure AWS credentials
+        uses: aws-actions/configure-aws-credentials@v4
+        with:
+          aws-region: ${{ secrets.AWS_REGION }}
+          role-to-assume: ${{ secrets.AWS_GHA_ROLE_ARN }}
+          role-session-name: gdgoc-prod-cd

OIDC 롤(예: AWS_GHA_ROLE_ARN) 준비가 어렵다면 현 방식 유지 가능하나, 중장기적으로 전환 권장.


33-55: 민감정보(.env) 패키징·전달 방식 재검토 권장.

AWS 자격증명, 메일 PW 등 고감도 비밀을 S3의 배포 ZIP에 포함시키는 구조는 노출면을 키웁니다. EC2 인스턴스 프로파일(IAM Role)로 대체하거나, SSM Parameter Store/Secrets Manager에서 런타임 주입하는 구조로 점진 전환을 제안합니다.

단계적 제안:

  • 단기: .env에서 AWS 액세스키 제거, 인스턴스 프로파일 사용.
  • 중기: Secrets Manager 참조를 애플리케이션/컨테이너 런타임에 통합.
  • 장기: GitHub OIDC + 최소 권한 롤, ECR 전환 검토.
gdgoc/docker-compose-dev.yml (2)

15-18: 중복/불필요한 .env 주입 제거.

env_file: .env로 이미 환경변수를 주입하고 있는데, 동일 .env 파일을 컨테이너에 볼륨 마운트(/app/.env)까지 할 필요는 거의 없습니다. 중복 주입은 혼란과 구성 드리프트를 야기합니다.

     volumes:
-      - /home/ubuntu/gdgoc-be-app-dev/.env:/app/.env
     env_file:
       - .env

필요 시 애플리케이션이 파일 자체를 읽도록 설계되어 있다면, env_file 대신 파일 마운트를 유지하는 한 가지 방식만 선택하세요.


8-12: 헬스체크 추가 권장.

운영 안정성을 위해 간단한 HTTP 헬스체크를 추가하면 CodeDeploy/오케스트레이션에서 상태 판단이 수월합니다.

예:

     ports:
       - "8080:8080"
+    healthcheck:
+      test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health | grep -q '\"status\":\"UP\"'"]
+      interval: 30s
+      timeout: 5s
+      retries: 5

엔드포인트는 실제 앱에 맞게 조정하세요.

gdgoc/deploy.dev.sh (2)

25-30: 과격한 정리 명령 재검토 (system/volume prune).

모든 미사용 리소스/볼륨을 강제로 삭제하면 디버깅/캐시가 사라지고, 다른 서비스에 영향이 갈 수 있습니다. 개발 서버라도 조심스럽게 사용하세요.

  • 최소한 docker volume prune -f는 제거하거나, 환경변수 플래그(예: PRUNE_VOLUMES=true)가 있을 때만 실행하도록 조건부 처리 권장.

6-20: sudo 남용/의존성 설치 경계.

CodeDeploy runas: root인 경우 sudo는 불필요합니다. CI/CD 중 시스템 패키지 설치는 실패 포인트가 되므로 AMI/이미지 레벨에서 선설치 또는 부트스트랩 스크립트로 분리하는 것을 고려하세요.

.github/workflows/deploy-dev.yml (6)

22-26: dev 이미지도 불변 태그 병행 푸시.

디버깅과 롤백 편의를 위해 latest 외에 커밋 SHA 태그를 추가하세요.

-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest
+          GIT_SHA=$(git rev-parse --short HEAD)
+          IMAGE=${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev
+          docker build -t "$IMAGE:latest" -t "$IMAGE:${GIT_SHA}" .
+          docker push "$IMAGE:latest"
+          docker push "$IMAGE:${GIT_SHA}"

33-55: .env 생성은 heredoc으로 단순화 (SC2129).

여러 번의 >> .env 대신 heredoc 사용으로 간결화하고, 공백/인용 처리 오류를 줄입니다.

-      - name: Create Deployment Package
-        run: |
-          echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
-          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env 
-          echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
-          echo "DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}" >> .env
-          echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
-          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
-          echo "GOOGLE_CLIENT_ID=${{ secrets.Google_CLIENT_ID }}" >> .env
-          ...
-          echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
+      - name: Create Deployment Package
+        run: |
+          cat > .env <<'EOF'
+          DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}
+          DB_HOST=${{ secrets.DB_HOST }}
+          DB_PORT=${{ secrets.DB_PORT }}
+          DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}
+          DB_USERNAME=${{ secrets.DB_USERNAME }}
+          DB_PASSWORD=${{ secrets.DB_PASSWORD }}
+          GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
+          GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
+          GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}
+          GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}
+          SELF_ISSUER=${{ secrets.SELF_ISSUER }}
+          SECRET_KEY=${{ secrets.SECRET_KEY }}
+          AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}
+          AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          AWS_REGION=${{ secrets.AWS_REGION }}
+          AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}
+          AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}
+          GMAIL=${{ secrets.GMAIL }}
+          GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}
+          EOF

57-62: AWS 자격 증명 구성은 OIDC 기반 공식 액션 사용 권장.

운영과 동일하게 dev도 aws-actions/configure-aws-credentials@v4 전환을 권장합니다. 현재 방식은 러너 환경에 설정이 남고, 보안상 최선이 아닙니다.


3-7: dev/prod 트리거 분리 권장.

현 구성상 dev/prod가 모두 push: main에서 동작합니다. 환경 분리 목적상 다음 중 하나로 분리하는 것을 권장합니다.

  • dev: push: [develop] 혹은 특정 경로(paths) 변경 시만 트리거
  • prod: 태그 릴리스(push: tags: ['v*']) 또는 보호된 브랜치 머지 시만 트리거
  • GitHub Environments(환경 승인/비밀 분리) 사용

55-66: 배포 ZIP 파일명 충돌 방지 및 추적성 향상.

dev도 커밋 SHA를 파일명에 포함하면 추적성과 병렬 배포 안정성이 좋아집니다.

-          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev.zip
+          GIT_SHA=$(git rev-parse --short HEAD)
+          mv deploy.zip "deploy-dev-${GIT_SHA}.zip"
+          aws s3 cp "deploy-dev-${GIT_SHA}.zip" "s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev-${GIT_SHA}.zip"
...
-            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy-dev.zip
+            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy-dev-${GIT_SHA}.zip

33-55: 민감정보 패키징 구조 개선(개발 환경에도 동일).

AWS 키/이메일 PW를 ZIP에 포함해 S3로 올리는 구조는 dev에서도 과합니다. EC2 인스턴스 프로파일, SSM/Secrets Manager, 또는 Docker secrets로 대체를 권장합니다.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 6c4b6fd and 68d51cd.

📒 Files selected for processing (9)
  • .github/workflows/deploy-dev.yml (1 hunks)
  • .github/workflows/deploy-prod.yml (3 hunks)
  • gdgoc/appspec.dev.yml (1 hunks)
  • gdgoc/appspec.prod.yml (1 hunks)
  • gdgoc/deploy.dev.sh (1 hunks)
  • gdgoc/deploy.prod.sh (2 hunks)
  • gdgoc/docker-compose-dev.yml (1 hunks)
  • gdgoc/src/main/resources/application-dev.yml (1 hunks)
  • gdgoc/src/main/resources/application-prod.yml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
gdgoc/src/main/resources/application-dev.yml (2)
gdgoc/src/main/java/inha/gdgoc/config/jwt/JwtProperties.java (1)
  • Setter (8-16)
gdgoc/src/main/java/inha/gdgoc/GdgocApplication.java (1)
  • EnableJpaAuditing (9-23)
🪛 actionlint (1.7.7)
.github/workflows/deploy-dev.yml

14-14: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


17-17: the runner of "docker/login-action@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


34-34: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


68-68: shellcheck reported issue in this script: SC1101:error:2:56: Delete trailing spaces after \ to break line (or use quotes for literal space)

(shellcheck)


68-68: shellcheck reported issue in this script: SC2215:warning:3:3: This flag is used as a command name. Bad line break or missing [ .. ]?

(shellcheck)

🪛 YAMLlint (1.37.1)
.github/workflows/deploy-dev.yml

[error] 36-36: trailing spaces

(trailing-spaces)


[error] 54-54: trailing spaces

(trailing-spaces)


[error] 70-70: trailing spaces

(trailing-spaces)

⏰ 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)
gdgoc/src/main/resources/application-prod.yml (1)

28-28: Flyway baseline 비활성화 전환: 운영 DB 상태 확인 필요

prod에서 baseline-on-migrate: false로 바뀌면, 이미 베이스라인 없이 운영 DB가 존재하는 경우 최초 마이그레이션이 실패할 수 있습니다. 운영 DB가 Flyway로 이미 버저닝되어 있거나, 최초 투입 시 별도 베이스라인(예: flyway baseline -baselineVersion=...) 절차가 있었는지 확인해 주세요. 배포 순서/롤백 전략에도 영향이 큽니다.

gdgoc/deploy.prod.sh (1)

31-38: 도커 허브 인증 누락 가능성

프라이빗 레포를 당겨야 한다면 docker login 절차가 필요합니다. CI가 .docker/config.json을 배포 서버에 전달하지 않는다면, DOCKER_HUB_USERNAME/DOCKER_HUB_TOKEN을 사용해 로그인 단계를 추가하세요.

gdgoc/appspec.dev.yml (2)

5-5: 배포 경로와 스크립트의 작업 디렉터리 일치 확인

dev는 destination: /home/ubuntu/gdgoc-be-app-dev입니다. deploy.dev.sh 내부 cd 경로와 Compose 파일 경로가 이와 일치하는지 확인해 주세요. prod 스크립트에는 누락된 -f 지정 이슈가 있으므로 dev도 동일하게 점검이 필요합니다.


9-11: 구성 패턴 일관성 양호

dev에서도 AfterInstall로 전환하여 환경 분리 흐름이 명확합니다. prod와의 네이밍·구조 일관성도 좋습니다.

Comment on lines 31 to 35
# 최신 이미지 가져오기
# shellcheck disable=SC2046
export $(grep -v '^#' .env | xargs)
# shellcheck disable=SC2086
docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

.env 로드 방식 취약: 공백/특수문자/주석에 취약

export $(grep ... | xargs)는 값에 공백/#/=가 포함되면 깨집니다. ShellCheck 경고를 억제하기보다 안전한 로딩으로 바꾸세요.

아래와 같이 변경 제안:

-# shellcheck disable=SC2046
-export $(grep -v '^#' .env | xargs)
+set -a
+# shellcheck disable=SC1091
+source .env
+set +a
📝 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
# 최신 이미지 가져오기
# shellcheck disable=SC2046
export $(grep -v '^#' .env | xargs)
# shellcheck disable=SC2086
docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
# 최신 이미지 가져오기
set -a
# shellcheck disable=SC1091
source .env
set +a
# shellcheck disable=SC2086
docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
🤖 Prompt for AI Agents
In gdgoc/deploy.prod.sh around lines 31 to 35, the current use of "export $(grep
-v '^#' .env | xargs)" is unsafe for .env entries containing spaces, hashes or
equals signs; replace it with a safe line-by-line parser: read the .env file
ignoring empty lines and comments, for each line split on the first = using
IFS='=' and read -r key value, trim surrounding quotes from the value, then
export the variable with its exact value (e.g., export "$key=$value"); ensure
you handle values containing spaces, #, or = correctly and avoid shellcheck
disables.

# shellcheck disable=SC2046
export $(grep -v '^#' .env | xargs)
# shellcheck disable=SC2086
docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

이미지 latest 사용: 재현 불가/예기치 않은 롤백

운영에서 :latest는 비재현성·롤백 혼선을 유발합니다. Git SHA 또는 릴리스 버전 태그로 고정하세요. CI에서 IMAGE_TAG를 주입받도록 권장합니다.

예시:

-docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
+IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
+docker pull "${DOCKER_HUB_USERNAME}/gdgoc-be-app:${IMAGE_TAG}"

그리고 compose 파일에서도 동일 태그를 사용하도록 .env 또는 compose override를 정렬해 주세요.

📝 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
docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
docker pull "${DOCKER_HUB_USERNAME}/gdgoc-be-app:${IMAGE_TAG}"
🤖 Prompt for AI Agents
In gdgoc/deploy.prod.sh around line 35, the script currently pulls the image
using the non-deterministic tag "latest", which can cause unreproducible
deployments and rollback confusion; change the script to use a specific tag
supplied by CI (e.g., use ${IMAGE_TAG} or ${GIT_SHA}) instead of :latest,
validate IMAGE_TAG is set and fail fast if missing, and update your Docker
Compose usage by aligning .env or the compose override to reference the same
IMAGE_TAG so both deploy script and compose use the identical immutable tag.

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: 5

Caution

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

⚠️ Outside diff range comments (2)
.github/workflows/deploy-prod.yml (2)

59-64: AWS 자격 증명 설정 방식 개선

수동 aws configure 대신 공식 액션을 사용하면 캐시/세션 갱신과 보안이 개선됩니다.

예시 교체안:

-      - name: Configure AWS credentials
-        run: |
-          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
-          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-          aws configure set region ${{ secrets.AWS_REGION }}
+      - name: Configure AWS credentials
+        uses: aws-actions/configure-aws-credentials@v4
+        with:
+          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          aws-region: ${{ secrets.AWS_REGION }}

35-55: 비밀 관리 범위 최소화(Dozzle 분리 권장)

현 단계에서는 .env에 모든 비밀이 모여 패키징됩니다. Dozzle에는 아이디/비밀번호만 필요하므로, dozzle.env를 별도 생성/압축하고 Dozzle 컨테이너에는 그 파일만 주입하도록 분리하는 것이 좋습니다. 이는 최소 권한 원칙을 충족하고 사고면적을 줄입니다.

예시(추가):

+          echo "DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}" > dozzle.env
+          echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> dozzle.env

그리고 zip 목록에 dozzle.env를 포함시키고, compose에서는 Dozzle의 env_file을 dozzle.env로 지정하세요.

♻️ Duplicate comments (3)
.github/workflows/deploy-dev.yml (3)

13-17: GitHub Actions 버전 업그레이드 필요 (checkout/login-action).

actionlint 경고대로 최신 메이저로 올려야 합니다. 최소 v4(Checkout), v3(Login) 권장입니다. 가능하면 커밋 SHA로 pinning도 검토하세요.

       - name: Checkout Repository
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4

       - name: Log in to Docker Hub
-        uses: docker/login-action@v2
+        uses: docker/login-action@v3

35-41: .env 생성 단계: 키 오탈자(DB_NAME_DEV) 및 트레일링 스페이스 제거.

compose 등에서 DB_NAME_DEV를 기대한다면 현재 DB_NAME로 기록하는 것은 오동작을 유발합니다. 또한 Line 36 끝 공백 제거가 필요합니다.

-          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env 
+          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env
           echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
-          echo "DB_NAME=${{ secrets.DB_NAME_DEV }}" >> .env
+          echo "DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}" >> .env
           echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
           echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env

다음 스크립트로 repo 내 reference 불일치를 점검해 주세요:

#!/bin/bash
# DB_NAME_DEV 사용 여부와 docker-compose-dev.yml에서의 참조를 확인
set -euo pipefail
rg -nC2 -e 'DB_NAME_DEV' -e 'DB_NAME=' gdgoc/docker-compose-dev.yml || true
rg -nC2 -e 'DB_NAME_DEV' -e 'DB_NAME=' --glob '!**/node_modules/**'

71-74: 역슬래시 뒤 공백으로 인한 쉘 파싱 오류(SC1101/SC2215).

\ 처럼 역슬래시 뒤 공백이 있어 파싱이 깨집니다. 공백 제거 또는 한 줄로 합치세요.

       - name: Deploy to AWS CodeDeploy
         run: |
           aws deploy create-deployment \
-            --application-name ${{ secrets.AWS_CODEDEPLOY_APP }} \  
+            --application-name ${{ secrets.AWS_CODEDEPLOY_APP }} \
             --deployment-group-name ${{ secrets.AWS_CODEDEPLOY_GROUP_DEV }} \
             --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy-dev.zip
🧹 Nitpick comments (12)
.github/workflows/deploy-dev.yml (8)

3-7: DEV 배포 트리거 브랜치 재검토(현재 main).

DEV 환경이라면 develop 브랜치 머지/푸시에 동작하는 것이 일반적입니다. 의도적으로 main에서 DEV로 배포하는 게 아니라면 develop으로 전환을 권장합니다. 필요 시 수동 트리거(workflow_dispatch)도 추가하세요.

다음 수정안을 검토해 주세요:

 on:
   push:
     branches:
-      - main
+      - develop
+  workflow_dispatch:

44-55: secrets 참조 스타일 통일(secrets.VAR 앞뒤 공백).

일부는 ${{secrets.VAR}}, 일부는 ${{ secrets.VAR }}로 혼재되어 있습니다. 가독성/일관성을 위해 통일하세요.

-          echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
-          echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
-          echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
+          echo "GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}" >> .env
+          echo "SELF_ISSUER=${{ secrets.SELF_ISSUER }}" >> .env
+          echo "SECRET_KEY=${{ secrets.SECRET_KEY }}" >> .env
-          echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
-          echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
-          echo "GMAIL=${{secrets.GMAIL}}" >> .env
-          echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
+          echo "AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}" >> .env
+          echo "AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}" >> .env
+          echo "GMAIL=${{ secrets.GMAIL }}" >> .env
+          echo "GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}" >> .env

22-26: 이미지 태깅: latest만 사용 지양, 커밋 SHA 태그 추가 권장.

배포 재현성과 롤백 용이성을 위해 SHA 태그를 함께 푸시하세요.

       - name: Build and Push Docker Image
         run: |
-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest
+          docker build \
+            -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest \
+            -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:${{ github.sha }} .
+          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest
+          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:${{ github.sha }}

65-68: S3 업로드 시 서버사이드 암호화 사용 권장.

민감한 .env가 포함된 zip입니다. SSE-S3 또는 KMS를 활성화하세요.

-          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev.zip
+          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev.zip --sse AES256
+# 또는 KMS 사용 시:
+# aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_B ACKET }}/deploy-dev.zip --sse aws:kms --sse-kms-key-id ${{ secrets.AWS_KMS_KEY_ID_DEV }}

57-58: .env 파일 권한 강화 및 정리.

워크플로 러너에서라도 최소 권한으로 생성 후 사용 종료 시 삭제를 권장합니다.

-          zip -r deploy.zip .env docker-compose-dev.yml deploy.dev.sh appspec.dev.yml
+          chmod 600 .env
+          zip -r deploy.zip .env docker-compose-dev.yml deploy.dev.sh appspec.dev.yml
+          rm -f .env

10-11: job에 environment와 concurrency 추가로 안전한 배포 보장.

환경 보호 규칙/비밀 스코프 분리를 위해 environment 지정, 동일 ref 중복 실행 방지를 위해 concurrency를 권장합니다.

   build-and-deploy:
     runs-on: ubuntu-latest
+    environment: dev
+    concurrency:
+      group: cd-dev-${{ github.ref }}
+      cancel-in-progress: true

1-7: 워크플로 최소 권한(permissions) 선언 추가.

OIDC를 쓰려면 id-token: write가 필요하고, 나머지는 read로 제한하는 것이 안전합니다.

 name: CD - DEV

 on:
   push:
     branches:
       - main
+
+permissions:
+  contents: read
+  id-token: write

56-56: 트레일링 스페이스 제거.

Line 56 끝 공백을 제거하세요. YAMLlint 에러를 예방합니다.

-          
+
gdgoc/docker-compose-prod.yml (1)

32-32: EOF 개행 누락

파일 끝 개행이 없어 linters가 실패합니다. 개행 1줄 추가하세요.

.github/workflows/deploy-prod.yml (3)

66-67: S3 업로드 시 서버측 암호화(SSE) 적용 권장

.env를 포함하는 배포 ZIP을 S3로 전송하므로 SSE 적용을 권장합니다. 버킷 기본 암호화가 없다면 명시적으로 지정하세요.

-          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy.zip
+          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy.zip --sse AES256

버킷에 기본 암호화/버전관리/퍼블릭 액세스 차단이 설정되어 있는지 확인 부탁드립니다.


22-25: 이미지 태그 불변성 확보(rollback/추적성 개선)

운영 이미지를 latest만 push하면 롤백·추적성이 떨어집니다. 커밋 SHA(또는 릴리스 버전) 태그를 함께 push하세요.

-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest
+          TAG=${GITHUB_SHA}
+          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:${TAG} .
+          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest
+          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:${TAG}

추가로 compose에서 prod 배포 시 해당 TAG를 참조하도록(예: sed로 바꿔치기) 하면 배포 재현성이 확보됩니다. 원하시면 해당 치환 로직도 제안드리겠습니다.


54-56: trailing space 제거

YAML Lint가 지적한 줄 끝 공백을 제거하세요. 빌드 경고를 줄이고 diff 노이즈를 방지합니다.

-          echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
-          
+          echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
+
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 68d51cd and cb5b763.

📒 Files selected for processing (4)
  • .github/workflows/deploy-dev.yml (1 hunks)
  • .github/workflows/deploy-prod.yml (3 hunks)
  • gdgoc/docker-compose-dev.yml (1 hunks)
  • gdgoc/docker-compose-prod.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • gdgoc/docker-compose-dev.yml
🧰 Additional context used
🪛 YAMLlint (1.37.1)
gdgoc/docker-compose-prod.yml

[error] 32-32: no new line character at the end of file

(new-line-at-end-of-file)

.github/workflows/deploy-dev.yml

[error] 36-36: trailing spaces

(trailing-spaces)


[error] 56-56: trailing spaces

(trailing-spaces)


[error] 72-72: trailing spaces

(trailing-spaces)

.github/workflows/deploy-prod.yml

[error] 56-56: trailing spaces

(trailing-spaces)

🪛 actionlint (1.7.7)
.github/workflows/deploy-dev.yml

14-14: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


17-17: the runner of "docker/login-action@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🔇 Additional comments (1)
.github/workflows/deploy-dev.yml (1)

27-31: 루트 복사 단계 적정성 확인(LGTM).

DEV 전용 아티팩트를 루트로 모아 패키징하는 접근은 목적에 부합합니다. 이후 단계(zip, S3, CodeDeploy)와 경로 일치도 OK입니다.

@kaswhy kaswhy merged commit 3030bf8 into develop Aug 23, 2025
2 of 3 checks passed
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: 3

Caution

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

⚠️ Outside diff range comments (5)
gdgoc/deploy.prod.sh (1)

25-30: 프로덕션에서 docker volume prune -f는 데이터 손실 위험.

컨테이너가 잠시 내려간 동안 “사용되지 않는” 볼륨으로 오인되어 삭제될 수 있습니다. DB/업로드 등 상태가 볼륨에 있다면 치명적입니다. 운영에서는 기본적으로 금지하거나, 대상을 명시적으로 제한하세요.

-# 불필요한 Docker 볼륨도 정리 (옵션)
-docker volume prune -f
+# (주의) 운영 환경에서는 볼륨 일괄 정리를 수행하지 않습니다.
+# 필요한 경우 특정 볼륨만 명시적으로 제거하세요.
+# docker volume rm <VOLUME_NAME>
.github/workflows/deploy-prod.yml (4)

22-26: PROD 이미지 latest 사용 중 — 불변 태그 병행 푸시 및 전달.

운영은 반드시 커밋 SHA 등 불변 태그를 사용하세요. 또한 해당 태그를 배포 스크립트에 전달해야 합니다.

-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app:latest
+          GIT_SHA="${GITHUB_SHA::12}"
+          IMAGE="${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app"
+          docker build -t "$IMAGE:latest" -t "$IMAGE:${GIT_SHA}" .
+          docker push "$IMAGE:latest"
+          docker push "$IMAGE:${GIT_SHA}"

그리고 아래 .env 생성 시 IMAGE_TAG=${GIT_SHA}를 함께 기록하세요(다음 코멘트에 포함).


33-55: .env 생성 방식/시크릿 취급 개선(Here‑doc, 따옴표/공백 안전).

여러 번 append 대신 Here‑doc으로 원자적으로 기록하고, IMAGE_TAG도 포함해 배포 스크립트와 일치시키세요.

-        run: |
-          echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
-          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env
-          echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
-          echo "DB_NAME=${{ secrets.DB_NAME }}" >> .env
-          echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
-          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
-          echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
-          echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
-          echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
-          echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
-          echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
-          echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
-          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
-          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
-          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
-          echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
-          echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
-          echo "GMAIL=${{secrets.GMAIL}}" >> .env
-          echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
-          echo "DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}" >> .env
-          echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
-          
-          zip -r deploy.zip .env docker-compose-prod.yml deploy.prod.sh appspec.yml
+        run: |
+          GIT_SHA="${GITHUB_SHA::12}"
+          cat > .env <<EOF
+          DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}
+          IMAGE_TAG=${GIT_SHA}
+          DB_HOST=${{ secrets.DB_HOST }}
+          DB_PORT=${{ secrets.DB_PORT }}
+          DB_NAME=${{ secrets.DB_NAME }}
+          DB_USERNAME=${{ secrets.DB_USERNAME }}
+          DB_PASSWORD=${{ secrets.DB_PASSWORD }}
+          GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
+          GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
+          GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}
+          GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}
+          SELF_ISSUER=${{ secrets.SELF_ISSUER }}
+          SECRET_KEY=${{ secrets.SECRET_KEY }}
+          # AWS credentials are intentionally omitted; use role/OIDC at runtime
+          AWS_REGION=${{ secrets.AWS_REGION }}
+          AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}
+          AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}
+          GMAIL=${{ secrets.GMAIL }}
+          GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}
+          DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}
+          DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}
+          EOF
+          chmod +x deploy.prod.sh
+          zip -r deploy.zip .env docker-compose-prod.yml deploy.prod.sh appspec.yml

47-49: AWS 자격증명을 .env에 저장하지 마세요.

운영 번들에 장기 키 포함은 금지 수준입니다. 인스턴스 Role/STS로 교체하고, 앱은 기본 자격증명 체인을 사용하세요.

-          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
-          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
-          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
+          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env

추가로 아래 “Configure AWS credentials” 스텝도 OIDC로 바꾸세요(다음 코멘트 참조).


59-63: aws configure → configure-aws-credentials@v4(OIDC) 전환.

운영 배포는 반드시 임시 크레덴셜을 통해 수행되도록 하세요.

-      - name: Configure AWS credentials
-        run: |
-          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
-          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-          aws configure set region ${{ secrets.AWS_REGION }}
+      - name: Configure AWS credentials
+        uses: aws-actions/configure-aws-credentials@v4
+        with:
+          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_PROD }}
+          aws-region: ${{ secrets.AWS_REGION }}

루트에 permissions도 추가 필요합니다(별도 블록 참조).

♻️ Duplicate comments (5)
.github/workflows/deploy-dev.yml (3)

47-49: AWS 액세스 키를 .env로 번들링 금지 — Role/OIDC로 대체.

장기 키를 배포 아티팩트에 포함하면 유출 리스크가 큽니다. 인스턴스/작업 Role 또는 GitHub OIDC를 사용하고 애플리케이션은 기본 자격증명 체인을 사용하도록 전환하세요.

-          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
-          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
-          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
+          # Use IAM Role/STS; keep only region if truly required by app
+          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env

애플리케이션이 정적 키를 직접 읽는다면, 해당 코드에서 Default Credentials Provider(EC2/ECS Role)를 사용하도록 변경이 필요합니다. 원하시면 변경 가이드 드리겠습니다.


59-63: aws configure 대신 공식 OIDC 액션 사용.

임시 크레덴셜(AssumeRole)로 교체하세요. 리스크/감사/회전성 개선됩니다.

-      - name: Configure AWS credentials
-        run: |
-          aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
-          aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-          aws configure set region ${{ secrets.AWS_REGION }}
+      - name: Configure AWS credentials
+        uses: aws-actions/configure-aws-credentials@v4
+        with:
+          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_DEV }}
+          aws-region: ${{ secrets.AWS_REGION }}

추가로 워크플로우 최상단에 권한을 선언해야 합니다(아래 별도 블록 참고).


69-74: 역슬래시 뒤 공백으로 인한 쉘 파싱 오류(SC1101/SC2215) 및 trailing space 제거.

현재 줄바꿈에 역슬래시 뒤 공백이 있어 실패할 수 있습니다. 한 줄로 정리하거나 공백 제거하세요.

-          aws deploy create-deployment \
-            --application-name ${{ secrets.AWS_CODEDEPLOY_APP }} \  
-            --deployment-group-name ${{ secrets.AWS_CODEDEPLOY_GROUP_DEV }} \
-            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy-dev.zip
+          aws deploy create-deployment --application-name "${{ secrets.AWS_CODEDEPLOY_APP }}" \
+            --deployment-group-name "${{ secrets.AWS_CODEDEPLOY_GROUP_DEV }}" \
+            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy-dev.zip
gdgoc/deploy.prod.sh (2)

32-35: .env 로드 방식 안전화 및 ShellCheck 억제 제거.

export $(grep ... | xargs)는 공백/#/= 포함 값에서 깨집니다. set -a + source 방식으로 교체하세요.

-# shellcheck disable=SC2046
-export $(grep -v '^#' .env | xargs)
+set -a
+# shellcheck disable=SC1091
+source .env
+set +a

35-35: 운영 이미지 latest 금지 — 불변 태그 사용.

재현/롤백 불가 문제를 유발합니다. CI에서 전달된 IMAGE_TAG(예: GIT_SHA)를 강제하세요.

-docker pull ${DOCKER_HUB_USERNAME}/gdgoc-be-app:latest
+IMAGE_TAG="${IMAGE_TAG:?IMAGE_TAG is required}"
+docker pull "${DOCKER_HUB_USERNAME}/gdgoc-be-app:${IMAGE_TAG}"

또한 compose 파일에서도 동일 태그를 사용하도록 .env의 IMAGE_TAG와 맞추세요.

🧹 Nitpick comments (12)
.github/workflows/deploy-dev.yml (5)

3-7: DEV 워크플로우 트리거 브랜치 재검토(현재 main).

개발 배포가 main 푸시에 함께 동작하면 PROD와 동시 배포/충돌 위험이 큽니다. 일반적으로 DEV는 develop(또는 feature/PR merge) 기준으로 분리합니다.

 on:
-  push:
-    branches:
-      - main
+  push:
+    branches:
+      - develop
+  workflow_dispatch:

22-26: 이미지 태깅 가시성 개선(sha 병행 태그 권장).

DEV라도 추적 가능성을 위해 latest 외에 커밋 SHA 태그를 함께 푸시하면 롤백과 디버깅이 쉬워집니다.

-          docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest .
-          docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev:latest
+          GIT_SHA="${GITHUB_SHA::12}"
+          IMAGE="${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-be-app-dev"
+          docker build -t "$IMAGE:latest" -t "$IMAGE:${GIT_SHA}" .
+          docker push "$IMAGE:latest"
+          docker push "$IMAGE:${GIT_SHA}"

65-68: S3 업로드 시 SSE 활성화 권장.

버킷 정책이 없다면 명시적으로 서버측 암호화를 지정하세요.

-          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev.zip
+          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy-dev.zip --sse AES256

36-36: trailing spaces 제거.

YAMLlint가 지적한 대로 해당 라인 말미 공백을 삭제하세요.

Also applies to: 56-56, 72-72


8-11: 동시 실행 억제와 환경 보호(concurrency/environments) 제안.

DEV 배포 중복 실행을 막고, GitHub Environments를 통해 시크릿/승인을 분리하면 운영 안정성이 좋아집니다.

아래처럼 추가를 고려해 주세요(참고용, 별도 위치 수정 필요):

concurrency:
  group: dev-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build-and-deploy:
    environment: dev
gdgoc/deploy.prod.sh (3)

1-3: 안전 기본값 추가(set -Eeuo pipefail) 및 오류 핸들링.

초반에 엄격 모드를 설정하면 배포 실패를 조기에 감지할 수 있습니다.

 #!/bin/bash
-# shellcheck disable=SC2164
+set -Eeuo pipefail
+trap 'echo "[ERROR] line ${LINENO} failed"; exit 1' ERR
+# shellcheck disable=SC2164

15-20: docker-compose 독립 바이너리 최신 다운로드 대신 공식 플러그인/버전 고정.

GitHub “latest” 바이너리를 직접 내려받으면 재현성/공급망 리스크가 있습니다. apt를 통한 Docker Compose plugin 설치 또는 특정 버전 고정(URL의 버전 명시)을 권장합니다.


31-31: .env 존재 체크 및 가독성.

배포 실패를 명확히 하기 위해 .env 유무를 사전에 확인하세요.

 # 최신 이미지 가져오기
+[ -f .env ] || { echo ".env not found"; exit 1; }
.github/workflows/deploy-prod.yml (4)

65-68: S3 업로드 시 SSE 지정.

-          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy.zip
+          aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/deploy.zip --sse AES256

12-18: 환경/동시성 보호 설정 제안.

환경 분리와 승인(Required reviewers)을 위해 Environments 활용 및 중복 실행 방지가 유용합니다.

예시(위치 조정 필요):

concurrency:
  group: prod-${{ github.ref }}
  cancel-in-progress: false

jobs:
  build-and-deploy:
    environment: prod

56-56: trailing space 제거.

YAMLlint가 지적한 라인 후행 공백을 삭제하세요.


69-74: CodeDeploy 파라미터 인용 및 구성(선택).

안전한 인용을 적용했고, 필요 시 배포 전략을 명시해 재현성을 높이세요.

-          aws deploy create-deployment \
-            --application-name ${{ secrets.AWS_CODEDEPLOY_APP }} \
-            --deployment-group-name ${{ secrets.AWS_CODEDEPLOY_GROUP }} \
-            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy.zip
+          aws deploy create-deployment \
+            --application-name "${{ secrets.AWS_CODEDEPLOY_APP }}" \
+            --deployment-group-name "${{ secrets.AWS_CODEDEPLOY_GROUP }}" \
+            --s3-location bucket=${{ secrets.AWS_S3_BUCKET }},bundleType=zip,key=deploy.zip
+            # --deployment-config-name CodeDeployDefault.AllAtOnce
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between cb5b763 and eb7e676.

📒 Files selected for processing (4)
  • .github/workflows/deploy-dev.yml (1 hunks)
  • .github/workflows/deploy-prod.yml (4 hunks)
  • gdgoc/deploy.dev.sh (1 hunks)
  • gdgoc/deploy.prod.sh (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • gdgoc/deploy.dev.sh
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/deploy-prod.yml

[error] 56-56: trailing spaces

(trailing-spaces)

.github/workflows/deploy-dev.yml

[error] 36-36: trailing spaces

(trailing-spaces)


[error] 56-56: trailing spaces

(trailing-spaces)


[error] 72-72: trailing spaces

(trailing-spaces)

🪛 actionlint (1.7.7)
.github/workflows/deploy-dev.yml

34-34: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)


70-70: shellcheck reported issue in this script: SC1101:error:2:56: Delete trailing spaces after \ to break line (or use quotes for literal space)

(shellcheck)


70-70: shellcheck reported issue in this script: SC2215:warning:3:3: This flag is used as a command name. Bad line break or missing [ .. ]?

(shellcheck)

@@ -0,0 +1,74 @@
name: CD - DEV
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

OIDC 사용 시 워크플로우 permissions 선언 필요.

OIDC 토큰 발급을 위해 id-token: write 권한이 필요합니다.

다음 블록을 워크플로우 루트에 추가하세요(파일 상단 근처).

permissions:
  id-token: write
  contents: read
🤖 Prompt for AI Agents
.github/workflows/deploy-dev.yml around lines 1 to 1: The workflow lacks a
permissions block required for OIDC token issuance; add a top-level permissions
declaration near the top of the file with id-token: write and contents: read so
the runner can request OIDC tokens and read repository contents. Ensure the
permissions block is placed at the workflow root (not inside a job or step) and
uses top-level YAML keys.

Comment on lines +33 to +55
- name: Create Deployment Package
run: |
echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env
echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
echo "DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}" >> .env
echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
echo "GMAIL=${{secrets.GMAIL}}" >> .env
echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
echo "DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}" >> .env
echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

.env 작성 방식 개선(따옴표/공백/SC2129).

여러 번의 echo >> 리다이렉트는 ShellCheck SC2129 경고를 유발하고, 값에 공백/특수문자가 있을 때 깨질 수 있습니다. Here‑doc으로 원자적으로 기록하세요. 또한 deploy 스크립트 실행 권한을 패키징 전에 보장하세요.

-          echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
-          echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env 
-          echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
-          echo "DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}" >> .env
-          echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
-          echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
-          echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
-          echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
-          echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
-          echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
-          echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
-          echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
-          echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
-          echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
-          echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
-          echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
-          echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
-          echo "GMAIL=${{secrets.GMAIL}}" >> .env
-          echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
-          echo "DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}" >> .env
-          echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
+          cat > .env <<'EOF'
+          DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}
+          DB_HOST=${{ secrets.DB_HOST }}
+          DB_PORT=${{ secrets.DB_PORT }}
+          DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}
+          DB_USERNAME=${{ secrets.DB_USERNAME }}
+          DB_PASSWORD=${{ secrets.DB_PASSWORD }}
+          GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
+          GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
+          GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}
+          GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}
+          SELF_ISSUER=${{ secrets.SELF_ISSUER }}
+          SECRET_KEY=${{ secrets.SECRET_KEY }}
+          # AWS credentials are intentionally omitted; use role/OIDC at runtime
+          AWS_REGION=${{ secrets.AWS_REGION }}
+          AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}
+          AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}
+          GMAIL=${{ secrets.GMAIL }}
+          GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}
+          DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}
+          DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}
+          EOF
+          chmod +x deploy.dev.sh
📝 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
- name: Create Deployment Package
run: |
echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
echo "DB_HOST=${{ secrets.DB_HOST }}" >> .env
echo "DB_PORT=${{ secrets.DB_PORT }}" >> .env
echo "DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}" >> .env
echo "DB_USERNAME=${{ secrets.DB_USERNAME }}" >> .env
echo "DB_PASSWORD=${{ secrets.DB_PASSWORD }}" >> .env
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
echo "GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}" >> .env
echo "GOOGLE_ISSUER=${{secrets.GOOGLE_ISSUER}}" >> .env
echo "SELF_ISSUER=${{secrets.SELF_ISSUER}}" >> .env
echo "SECRET_KEY=${{secrets.SECRET_KEY}}" >> .env
echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env
echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env
echo "AWS_REGION=${{ secrets.AWS_REGION }}" >> .env
echo "AWS_RESOURCE_BUCKET=${{secrets.AWS_RESOURCE_BUCKET}}" >> .env
echo "AWS_TEST_RESOURCE_BUCKET=${{secrets.AWS_TEST_RESOURCE_BUCKET}}" >> .env
echo "GMAIL=${{secrets.GMAIL}}" >> .env
echo "GMAIL_PASSWORD=${{secrets.GMAIL_PASSWORD}}" >> .env
echo "DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}" >> .env
echo "DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}" >> .env
- name: Create Deployment Package
run: |
cat > .env <<'EOF'
DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}
DB_HOST=${{ secrets.DB_HOST }}
DB_PORT=${{ secrets.DB_PORT }}
DB_NAME_DEV=${{ secrets.DB_NAME_DEV }}
DB_USERNAME=${{ secrets.DB_USERNAME }}
DB_PASSWORD=${{ secrets.DB_PASSWORD }}
GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}
GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }}
GOOGLE_ISSUER=${{ secrets.GOOGLE_ISSUER }}
SELF_ISSUER=${{ secrets.SELF_ISSUER }}
SECRET_KEY=${{ secrets.SECRET_KEY }}
# AWS credentials are intentionally omitted; use role/OIDC at runtime
AWS_REGION=${{ secrets.AWS_REGION }}
AWS_RESOURCE_BUCKET=${{ secrets.AWS_RESOURCE_BUCKET }}
AWS_TEST_RESOURCE_BUCKET=${{ secrets.AWS_TEST_RESOURCE_BUCKET }}
GMAIL=${{ secrets.GMAIL }}
GMAIL_PASSWORD=${{ secrets.GMAIL_PASSWORD }}
DOZZLE_USERNAME=${{ secrets.DOZZLE_USERNAME }}
DOZZLE_PASSWORD=${{ secrets.DOZZLE_PASSWORD }}
EOF
chmod +x deploy.dev.sh
🧰 Tools
🪛 actionlint (1.7.7)

34-34: shellcheck reported issue in this script: SC2129:style:2:1: Consider using { cmd1; cmd2; } >> file instead of individual redirects

(shellcheck)

🪛 YAMLlint (1.37.1)

[error] 36-36: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
.github/workflows/deploy-dev.yml around lines 33 to 55: the current step appends
many secrets with repeated echo/>> which triggers ShellCheck SC2129 and can
break on spaces/special chars; replace the repeated echo lines with a single
here-document to atomically write the .env file (ensuring values are not subject
to word-splitting or globbing), quote variable expansions where appropriate, and
set the deploy script executable (chmod +x) before packaging so it runs
correctly during deployment.

@@ -1,4 +1,4 @@
name: Deploy to EC2 via Docker Hub and CodeDeploy
name: CD - PROD
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

OIDC 사용을 위한 permissions 선언.

프로덕션 워크플로우 루트에 다음 권한이 필요합니다.

permissions:
  id-token: write
  contents: read
🤖 Prompt for AI Agents
.github/workflows/deploy-prod.yml around lines 1 to 1: the workflow is missing
the required top-level permissions for OIDC; add a top-level permissions mapping
with "id-token: write" and "contents: read" (properly indented as top-level keys
in the YAML, placed directly under the workflow name and before jobs) to enable
OIDC token issuance for the production deployment workflow and ensure valid YAML
syntax.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] dozzle 추가 [FEAT] prod, dev 환경 분리

2 participants