v2의 CICD의 파이프라인 - 100-hours-a-week/KTB4-17th-wiki GitHub Wiki
기존 설계 문서: V2 CI Pipeline
Backend CI
1. 단위 테스트 도입
단위 테스트는 외부 시스템과의 연결을 최소화하고, 테스트 대상 클래스의 동작을 독립적으로 검증한다.
| 도구 | 역할 |
|---|---|
| JUnit 5 | 테스트를 실행하고 결과를 검증한다. |
| Mockito | 실제 데이터베이스나 외부 서버 대신 가짜 객체와 응답을 사용하여 테스트 대상 클래스만 검증한다. |
| AssertJ | 예외 타입, 에러 코드 등의 검증 조건을 읽기 쉬운 문장 형태로 작성한다. |
| MockRestServiceServer | 외부 AI 서버를 가짜로 구성하여 요청 형식과 응답·오류 처리 동작을 검증한다. |
2. API 테스트 도입
API 테스트는 스프링 애플리케이션의 구성 요소가 실제로 연결된 상태에서 요청과 응답이 올바르게 처리되는지 검증한다.
| 도구 | 역할 |
|---|---|
| JUnit 5, Mockito, AssertJ | 테스트 실행, 객체 대체 및 결과 검증에 사용한다. |
| Spring Boot Test | 스프링 컨텍스트를 실행하여 구성 요소 간 연동 상태를 검증한다. |
| MockMvc | 실제 네트워크 포트를 열지 않고 Spring MVC 계층에 가상의 HTTP 요청을 전송한다. |
3. 의존성 검사를 시크릿 보안 검사로 변경
기존 의존성 검사는 의존성 트리를 출력하는 데 그쳐 보안 취약점이 발견되어도 CI가 실패하지 않았다. 이를 보완하기 위해 Gitleaks를 도입하여 전체 커밋 기록에 비밀번호, API 키, 토큰 등의 민감 정보가 포함되어 있는지 검사한다.
- Gitleaks 공식 이미지를 확인한다.
- 컨테이너를 생성한다.
- 현재 저장소를 컨테이너에 연결한다.
- Gitleaks 명령어를 실행한다.
- 검사 결과에 따라 작업의 성공 여부를 결정한다.
Backend CI 워크플로
name: CI backend
on:
push:
branches:
- chore/backend-CD
pull_request:
branches:
- dev
permissions:
contents: write
pull-requests: write
jobs:
backend_ci:
runs-on: ubuntu-latest
steps:
- name: Check PR source
uses: actions/checkout@v7
with:
fetch-depth: 0 # 커밋 기록 전체를 볼 수 있도록 전부 받옴 =0 (시크릿 스캔에서 사용)
- name: Set up Java
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: "25"
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v6
- name: Formatter Check
run: ./gradlew spotlessCheck
# 의존성 검사 대신 Gitleaks으로 변경
- name: Secret Scan
env:
# PR이면 PR 브랜치의 최신 커밋이나 push면 방금 올라온 커밋만 검사
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:v8.30.1 \
git /repo --log-opts="-1 $COMMIT" --redact --no-banner --verbose
#단위 테스트
- name: Unit Test
run: ./gradlew unitTest
#Api테스트
- name: API Test
run: ./gradlew apiTest
#테스트 레포트 작성
- name: Upload Test Report
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-report
path: build/reports/tests
retention-days: 7
- name: Build
run: ./gradlew clean bootJar -x test
Frontend
1. 단위 테스트 도입
src 디렉터리 아래의 모든 *.test.js 파일을 실행하도록 단위 테스트 단계를 추가한다. 테스트 파일이 늘어나더라도 CI 설정에 각 파일을 별도로 추가할 필요가 없다.
2. CodeQL 보안 검사 도입
CodeQL은 소스 코드를 분석 가능한 데이터 형태로 변환한 뒤, 알려진 취약점 패턴을 쿼리로 검색하는 정적 분석 도구다.
프런트엔드 영역은 전담 개발자가 별도로 배정되어 있지 않고 AI를 활용해 코드를 작성하므로, 일반적인 코드 리뷰만으로 보안 취약점을 충분히 식별하기 어려울 수 있다. 이에 따라 dev 브랜치를 대상으로 Pull Request가 생성되거나 변경될 때마다 CodeQL 정적 분석을 수행하여 잠재적인 보안 문제를 자동으로 탐지한다.
CodeQL 분석은 일반적인 Lint, 타입 검사 및 빌드보다 상대적으로 많은 시간이 소요되며 기존 CI 작업의 결과를 선행 조건으로 요구하지 않는다. 따라서 CodeQL을 기존 CI와 독립된 작업으로 구성하고 병렬 실행한다. 이를 통해 전체 검증 시간을 줄이고 일반 품질 검사와 보안 분석의 결과를 명확히 구분할 수 있다.
필요한 경우 브랜치 보호 규칙에서 일반 CI와 CodeQL 분석을 모두 필수 상태 검사로 지정하여, 두 검사가 모두 통과해야 dev 브랜치에 병합할 수 있도록 관리한다.
Frontend CI 워크플로
name: Frontend CI
# package.json은 프로젝트가 요구하는 패키지를 정의하고,
# package-lock.json은 실제로 설치되는 패키지 버전을 고정한다.
# 별도의 TypeScript 검사가 필요하지 않아 해당 단계는 제거했다.
on:
pull_request:
branches:
- dev
# PR 생성·변경 또는 수동 실행 시에만 CI를 수행한다.
workflow_dispatch:
permissions:
contents: read
jobs:
feature_ci:
name: Feature CI
runs-on: ubuntu-latest
steps:
- name: Check source
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: "24"
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Biome Check
run: npm run lint:biome
- name: HTML Lint
run: npm run lint:html
- name: CSS Lint
run: npm run lint:css
# 현재 제외된 의존성 취약점 검사
# - name: Dependency Vulnerability Check
# run: npx -y audit-ci@7 --high --allowlist GHSA-vfj7-8cjw-p6xm
- name: Unit Test
run: node --test "src/**/*.test.js"
- name: Build
run: npm run build
# CodeQL은 선행 작업이 필요하지 않으므로 일반 CI와 병렬로 실행한다.
codeql:
name: CodeQL Analysis
runs-on: ubuntu-latest
permissions:
contents: read
actions: read
security-events: write
steps:
- name: Checkout source
uses: actions/checkout@v7
with:
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: javascript-typescript
build-mode: none
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
AI
1. 테스트 분리
현재 단위 테스트와 API 테스트가 모두 tests 디렉터리에 혼재되어 있으므로, 파일명 패턴을 기준으로 테스트 대상을 구분한다.
- 단위 테스트:
tests/test_*_api.py패턴에 해당하는 파일을 제외하고 실행한다. - API 테스트:
tests/test_*_api.py패턴에 해당하는 파일만 실행한다.
AI CI 워크플로
name: CI AI
on:
pull_request:
branches:
- dev
jobs:
feature_ci:
name: AI feature validation
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check source
uses: actions/checkout@v7
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.12"
enable-cache: true
- name: Install dependencies
run: uv sync --all-groups --locked
- name: Lint
run: uv run ruff check .
- name: Formatter Check
run: uv run ruff format --check .
- name: Dependency Vulnerability Check
run: uvx pip-audit .
# API 테스트 파일을 제외한 단위 테스트 실행
- name: Unit Test
run: uv run pytest --ignore-glob='tests/test_*_api.py'
# 핵심 기능 API 테스트 실행
- name: API Test
run: uv run pytest tests/test_*_api.py
- name: Build
run: uv run python -m compileall -q .