Skip to content

Chore: Update CI/CD workflows#1

Merged
dungbik merged 2 commits intomainfrom
chore/ci-cd
Feb 18, 2026
Merged

Chore: Update CI/CD workflows#1
dungbik merged 2 commits intomainfrom
chore/ci-cd

Conversation

@dungbik
Copy link
Contributor

@dungbik dungbik commented Feb 18, 2026

Summary by CodeRabbit

릴리스 노트

  • Chores
    • 메인 브랜치 푸시 시 애플리케이션 빌드·테스트·의존성 검사하는 지속적 통합(CI) 워크플로우 추가
    • CI 완료 후 자동으로 이미지를 빌드·태깅·푸시하는 지속적 배포(CD) 워크플로우 추가
    • 멀티스테이지 Docker 이미지 빌드로 Java 애플리케이션 패키징 및 컨테이너 환경(타임존 설정 포함)에서 8083 포트로 실행 설정 추가

@dungbik dungbik self-assigned this Feb 18, 2026
@dungbik dungbik added the enhancement New feature or request label Feb 18, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 18, 2026

No actionable comments were generated in the recent review. 🎉


Walkthrough

메인 브랜치에 대해 Gradle 기반 CI(빌드·테스트·의존성 검사)와 CI 성공 시 Docker 이미지를 빌드해 DockerHub에 푸시하는 CD GitHub Actions 워크플로우 및 멀티스테이지 Dockerfile을 추가합니다.

Changes

Cohort / File(s) Summary
워크플로우
.github/workflows/ci.yml, .github/workflows/cd.yml
CI: Gradle 빌드·테스트 실행 및 Dependency-Check 보고서 생성. CD: CI 완료 시 트리거되어 DockerHub 인증, 이미지 메타데이터 추출 및 이미지 빌드·푸시 수행.
컨테이너 이미지
Dockerfile
멀티스테이지 Dockerfile 추가: gradle:8-jdk21로 빌드해 Spring Boot JAR 생성 후 eclipse-temurin:21-jre 기반 런타임 이미지에서 JAR 실행 설정(타임존 설정 포함).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Dev as 개발자 (푸시)
    participant GH as GitHub Actions
    participant Runner as Actions Runner
    participant DockerMeta as docker/metadata-action
    participant BuildPush as docker/build-push-action
    participant DockerHub as DockerHub Registry

    Dev->>GH: 코드 푸시 (main)
    GH->>Runner: CI 워크플로우 실행 (빌드·테스트·의존성 검사)
    Runner-->>GH: CI 성공
    GH->>Runner: CD 워크플로우 실행 (on: workflow_run)
    Runner->>DockerMeta: 이미지 태그/라벨 생성 요청
    DockerMeta-->>Runner: 태그/라벨 출력
    Runner->>BuildPush: 이미지 빌드 및 푸시 (메타데이터 포함)
    BuildPush->>DockerHub: 이미지 업로드
    DockerHub-->>GH: 푸시 완료 응답
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 깡충, 코드가 춤을 추네—
푸시 한 번에 빌드와 테스트,
컨테이너는 빛의 속도로 둥실둥실,
허허, DockerHub에 집들이하러 간다! 🥕🚀

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Chore: Update CI/CD workflows' accurately summarizes the main changes in the pull request, which adds GitHub Actions CI/CD workflows (cd.yml, ci.yml) and a Dockerfile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/ci-cd

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🧹 Nitpick comments (2)
.github/workflows/cd.yml (1)

17-17: docker/login-action 사용 권장

공식 Docker GitHub Actions 문서는 docker/login-action@v3을 DockerHub 인증 표준 방식으로 권장합니다. run: echo | docker login 방식은 작업 종료 후 자격증명 정리(docker logout)가 자동으로 이루어지지 않습니다.

♻️ 제안하는 리팩토링
-      - name: Login to DockerHub
-        run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
+      - name: Login to DockerHub
+        uses: docker/login-action@v3
+        with:
+          username: ${{ secrets.DOCKER_USERNAME }}
+          password: ${{ secrets.DOCKER_PASSWORD }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/cd.yml at line 17, The workflow currently logs into Docker
using a shell run step (echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u
"${{ secrets.DOCKER_USERNAME }}" --password-stdin) which doesn't auto-clean
credentials; replace that run step with the official action by using uses:
docker/login-action@v3 and pass with: username: ${{ secrets.DOCKER_USERNAME }}
and password: ${{ secrets.DOCKER_PASSWORD }} so the action handles secure
login/logout and credential cleanup.
Dockerfile (1)

1-7: [선택적 개선] Gradle 의존성 레이어 캐시 분리

현재 구조에서는 소스 파일이 변경될 때마다 의존성 다운로드부터 재실행됩니다. 의존성 다운로드 단계를 분리하면 소스 변경 시 캐시를 재사용할 수 있습니다.

♻️ 제안하는 레이어 캐싱 최적화
 FROM gradle:8-jdk21 AS build
 WORKDIR /app
 
 COPY build.gradle.kts settings.gradle.kts ./
+RUN gradle dependencies --no-daemon
+
 COPY src ./src
 
 RUN gradle bootJar --no-daemon
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 1 - 7, Separate dependency resolution into its own
layer by first copying only build files (COPY build.gradle.kts
settings.gradle.kts ./) and running a Gradle step to download dependencies
(e.g., RUN gradle dependencies --no-daemon or RUN gradle build -x test
--no-daemon) before copying the src directory; then keep the existing COPY src
./ and RUN gradle bootJar --no-daemon so source changes do not invalidate the
dependency cache.
🤖 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/cd.yml:
- Around line 3-6: The CD workflow currently triggers on push (on: push:
branches: [main]) which allows deployment even if CI failed; change the trigger
to use the workflow_run event so the CD only runs after the CI workflow
completes successfully — replace the on: push block with on: workflow_run:
workflows: ["CI"] (or the actual CI workflow name), types: [completed], and add
a conditional to the job(s) if needed to ensure
github.event.workflow_run.conclusion == 'success'; update any job-level if
expressions referencing github.ref to use
github.event.workflow_run.head_branch/head_sha where appropriate.

In @.github/workflows/ci.yml:
- Around line 44-49: The workflow step named "Run dependency check" currently
pins the action as dependency-check/Dependency-Check_Action@main which is a
branch ref; change it to the specific commit SHA for the v1.1.0 release (replace
`@main` with @<v1.1.0-commit-sha>) and add an inline comment indicating the
release version and SHA (e.g., "v1.1.0 - <commit-sha>") so the action is fixed
to a known release and the version is explicit.

In `@Dockerfile`:
- Around line 13-17: The RUN instruction in the Dockerfile installs tzdata
without suppressing recommended packages; update the RUN line that calls apt-get
install -y tzdata to include the --no-install-recommends flag so it becomes
apt-get install -y --no-install-recommends tzdata (keep the surrounding apt-get
update, timezone symlink/echo and rm -rf /var/lib/apt/lists/* steps intact) to
avoid pulling unnecessary recommended packages into the image.
- Around line 19-23: The Dockerfile hardcodes reaction-0.0.1-SNAPSHOT.jar in
both COPY and ENTRYPOINT causing builds to break on version changes; update the
Dockerfile to COPY the built jar using a wildcard (e.g., COPY --from=build
/app/build/libs/*.jar /app/), capture the actual filename into a Docker ARG/ENV
or rename the copied jar to a stable name (e.g., reaction.jar) so ENTRYPOINT can
reliably run java -jar reaction.jar; modify the ENTRYPOINT to reference the
stable name or the ARG (java -jar ${JAR_NAME}) and ensure the build stage still
outputs a single jar to avoid ambiguous wildcard matches.
- Around line 9-23: The Dockerfile currently runs the image as root; add a
non-root user and switch to it before ENTRYPOINT to avoid running as root
(address DS-0002). In the Dockerfile create a user/group (e.g., appuser), set
ownership of the copied artifact (reaction-0.0.1-SNAPSHOT.jar) to that user
(chown), and add a USER appuser line so the ENTRYPOINT ["java", "-jar",
"reaction-0.0.1-SNAPSHOT.jar"] runs unprivileged; ensure any directories the app
needs (WORKDIR /app) are writable by that user.

---

Nitpick comments:
In @.github/workflows/cd.yml:
- Line 17: The workflow currently logs into Docker using a shell run step (echo
"${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME
}}" --password-stdin) which doesn't auto-clean credentials; replace that run
step with the official action by using uses: docker/login-action@v3 and pass
with: username: ${{ secrets.DOCKER_USERNAME }} and password: ${{
secrets.DOCKER_PASSWORD }} so the action handles secure login/logout and
credential cleanup.

In `@Dockerfile`:
- Around line 1-7: Separate dependency resolution into its own layer by first
copying only build files (COPY build.gradle.kts settings.gradle.kts ./) and
running a Gradle step to download dependencies (e.g., RUN gradle dependencies
--no-daemon or RUN gradle build -x test --no-daemon) before copying the src
directory; then keep the existing COPY src ./ and RUN gradle bootJar --no-daemon
so source changes do not invalidate the dependency cache.

Comment on lines +44 to +49
- name: Run dependency check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'FlipNote-Reaction'
path: '.'
format: 'HTML'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

GitHub action security best practices pinning commit SHA version tags

💡 Result:

GitHub Actions security best practices for version pinning (commit SHA vs tags)

  • Prefer pinning every third‑party action to a full, immutable commit SHA (40 chars) rather than a branch or tag, to reduce supply‑chain risk (tags can be moved). Example:
    uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7  [1][2]
  • Pin SHAs that correspond to a published release/tag, and add a comment with the human version (e.g., # v4.1.7) to keep workflows readable and updateable. [2]
  • Verify the SHA is from the action’s official repository (not a fork) before pinning. [1]
  • Keep pinned SHAs updated with automation (e.g., Dependabot “version updates” for Actions) so you don’t trade supply‑chain risk for stale dependencies. [2]
  • Enforce SHA pinning via policy (org/repo/enterprise settings) so unpinned workflows can’t be introduced. [1][3]
  • Audit third‑party actions you rely on (especially those that touch secrets or repo contents). [1]

Sources

[1] GitHub Docs — Security hardening for GitHub Actions (docs.github.com)
[2] GitHub Well-Architected — Securing GitHub Actions Workflows (wellarchitected.github.com)
[3] GitHub Changelog — Actions policy now supports … SHA pinning (github.blog)

Citations:


🌐 Web query:

dependency-check/Dependency-Check_Action releases tags GitHub

💡 Result:

dependency-check/Dependency-Check_Action has 2 releases/tags on GitHub:

  • 1.1.0 (“Added extra parameters”) — Apr 28, 2021 (latest) [1][2]
  • 1.0.0 (“Dependency Check Action - Initial version”) — Feb 28, 2021 [1][2]

You can view them here:

Sources: [1] https://github.com/dependency-check/Dependency-Check_Action/tags [2] https://github.com/dependency-check/Dependency-Check_Action/releases


🌐 Web query:

dependency-check/Dependency-Check_Action v1.1.0 commit SHA GitHub

💡 Result:

For dependency-check/Dependency-Check_Action v1.1.0 (tag 1.1.0), the commit SHA is:

75ba02d6183445fe0761d26e836bde58b1560600 [1][2]


🏁 Script executed:

#!/bin/bash
# Find the commit SHA for dependency-check/Dependency-Check_Action v1.1.0 release
# Using curl to query GitHub API
curl -s "https://api.github.com/repos/dependency-check/Dependency-Check_Action/releases/tags/1.1.0" | jq -r '.target_commitish' 2>/dev/null || echo "Check failed"

Repository: FlipNoteTeam/FlipNote-Reaction

Length of output: 78


dependency-check/Dependency-Check_Action을 @main으로 고정하면 공급망 위협 발생

@main은 브랜치 참조이므로 해당 액션 저장소의 변경이 즉시 워크플로우에 영향을 미칩니다. GitHub 보안 강화 가이드라인은 서드파티 액션을 특정 커밋 SHA로 고정할 것을 권장합니다.

해당 액션은 v1.1.0(최신 릴리스, 2021년 4월)이 존재합니다. 다음과 같이 릴리스 버전의 커밋 SHA로 고정하고 버전 주석을 추가하세요:

-        uses: dependency-check/Dependency-Check_Action@main
+        uses: dependency-check/Dependency-Check_Action@75ba02d6183445fe0761d26e836bde58b1560600 # v1.1.0

이렇게 하면 공급망 위협을 줄이면서도 어떤 릴리스 버전을 사용하고 있는지 명확하게 유지할 수 있습니다.

📝 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: Run dependency check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'FlipNote-Reaction'
path: '.'
format: 'HTML'
- name: Run dependency check
uses: dependency-check/Dependency-Check_Action@75ba02d6183445fe0761d26e836bde58b1560600 # v1.1.0
with:
project: 'FlipNote-Reaction'
path: '.'
format: 'HTML'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 44 - 49, The workflow step named "Run
dependency check" currently pins the action as
dependency-check/Dependency-Check_Action@main which is a branch ref; change it
to the specific commit SHA for the v1.1.0 release (replace `@main` with
@<v1.1.0-commit-sha>) and add an inline comment indicating the release version
and SHA (e.g., "v1.1.0 - <commit-sha>") so the action is fixed to a known
release and the version is explicit.

Comment on lines +9 to +23
FROM eclipse-temurin:21-jre
WORKDIR /app

ENV TZ=Asia/Seoul
RUN apt-get update \
&& apt-get install -y tzdata \
&& ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& rm -rf /var/lib/apt/lists/*

COPY --from=build /app/build/libs/reaction-0.0.1-SNAPSHOT.jar .

EXPOSE 8083

ENTRYPOINT ["java", "-jar", "reaction-0.0.1-SNAPSHOT.jar"]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

컨테이너가 root 사용자로 실행됨 (보안 취약점)

USER 명령이 없어 런타임 컨테이너가 root 권한으로 실행됩니다. 컨테이너 탈출 시 호스트에 대한 root 접근이 가능해집니다. (Trivy DS-0002)

🔒 제안하는 수정 - 비루트 사용자 추가
 FROM eclipse-temurin:21-jre
 WORKDIR /app
 
 ENV TZ=Asia/Seoul
 RUN apt-get update \
     && apt-get install -y --no-install-recommends tzdata \
     && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
     && echo $TZ > /etc/timezone \
     && rm -rf /var/lib/apt/lists/*
 
+RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
+
 COPY --from=build /app/build/libs/reaction-0.0.1-SNAPSHOT.jar .
 
+USER appuser
+
 EXPOSE 8083
 
 ENTRYPOINT ["java", "-jar", "reaction-0.0.1-SNAPSHOT.jar"]
🧰 Tools
🪛 Trivy (0.69.1)

[error] 13-17: 'apt-get' missing '--no-install-recommends'

'--no-install-recommends' flag is missed: 'apt-get update && apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && rm -rf /var/lib/apt/lists/*'

Rule: DS-0029

Learn more

(IaC/Dockerfile)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 9 - 23, The Dockerfile currently runs the image as
root; add a non-root user and switch to it before ENTRYPOINT to avoid running as
root (address DS-0002). In the Dockerfile create a user/group (e.g., appuser),
set ownership of the copied artifact (reaction-0.0.1-SNAPSHOT.jar) to that user
(chown), and add a USER appuser line so the ENTRYPOINT ["java", "-jar",
"reaction-0.0.1-SNAPSHOT.jar"] runs unprivileged; ensure any directories the app
needs (WORKDIR /app) are writable by that user.

Comment on lines +13 to +17
RUN apt-get update \
&& apt-get install -y tzdata \
&& ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& rm -rf /var/lib/apt/lists/*
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

apt-get install--no-install-recommends 플래그 누락

불필요한 권장 패키지가 함께 설치되어 이미지 크기가 커지고 공격 표면이 넓어집니다. (Trivy DS-0029)

🛡️ 제안하는 수정
 RUN apt-get update \
-    && apt-get install -y tzdata \
+    && apt-get install -y --no-install-recommends tzdata \
     && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
     && echo $TZ > /etc/timezone \
     && rm -rf /var/lib/apt/lists/*
📝 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
RUN apt-get update \
&& apt-get install -y tzdata \
&& ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update \
&& apt-get install -y --no-install-recommends tzdata \
&& ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone \
&& rm -rf /var/lib/apt/lists/*
🧰 Tools
🪛 Trivy (0.69.1)

[error] 13-17: 'apt-get' missing '--no-install-recommends'

'--no-install-recommends' flag is missed: 'apt-get update && apt-get install -y tzdata && ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && rm -rf /var/lib/apt/lists/*'

Rule: DS-0029

Learn more

(IaC/Dockerfile)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 13 - 17, The RUN instruction in the Dockerfile
installs tzdata without suppressing recommended packages; update the RUN line
that calls apt-get install -y tzdata to include the --no-install-recommends flag
so it becomes apt-get install -y --no-install-recommends tzdata (keep the
surrounding apt-get update, timezone symlink/echo and rm -rf
/var/lib/apt/lists/* steps intact) to avoid pulling unnecessary recommended
packages into the image.

Comment on lines +19 to +23
COPY --from=build /app/build/libs/reaction-0.0.1-SNAPSHOT.jar .

EXPOSE 8083

ENTRYPOINT ["java", "-jar", "reaction-0.0.1-SNAPSHOT.jar"]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

하드코딩된 SNAPSHOT JAR 이름으로 인한 버전 변경 시 빌드 실패

reaction-0.0.1-SNAPSHOT.jarCOPYENTRYPOINT 양쪽에 하드코딩되어 있어, build.gradle.kts에서 버전이나 아카이브명이 변경되면 Docker 빌드가 즉시 실패합니다. 와일드카드로 복사 후 고정 이름으로 변경하는 방식이 표준입니다.

🐛 제안하는 수정
-COPY --from=build /app/build/libs/reaction-0.0.1-SNAPSHOT.jar .
+COPY --from=build /app/build/libs/*.jar app.jar
 
 EXPOSE 8083
 
-ENTRYPOINT ["java", "-jar", "reaction-0.0.1-SNAPSHOT.jar"]
+ENTRYPOINT ["java", "-jar", "app.jar"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 19 - 23, The Dockerfile hardcodes
reaction-0.0.1-SNAPSHOT.jar in both COPY and ENTRYPOINT causing builds to break
on version changes; update the Dockerfile to COPY the built jar using a wildcard
(e.g., COPY --from=build /app/build/libs/*.jar /app/), capture the actual
filename into a Docker ARG/ENV or rename the copied jar to a stable name (e.g.,
reaction.jar) so ENTRYPOINT can reliably run java -jar reaction.jar; modify the
ENTRYPOINT to reference the stable name or the ARG (java -jar ${JAR_NAME}) and
ensure the build stage still outputs a single jar to avoid ambiguous wildcard
matches.

@dungbik dungbik merged commit a742653 into main Feb 18, 2026
3 checks passed
@dungbik dungbik deleted the chore/ci-cd branch February 18, 2026 07:41
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.

1 participant