[V1] Backend CI - 100-hours-a-week/KTB4-10th-Cloud GitHub Wiki

[ 1. 고려사항 ]

<3단계 내용 중 일부>


#### 3.1.1. 우리팀은 git flow 방식을 사용

- main(배포) - dev(중간 병합) - feature(기능)
- 브랜치에 따라 CI의 구성을 따로 고려

#### 3.1.2. 빌드 구성에서 캐시 정책

- 깃 공유 저장소는 프라이빗과 다르게 Github actions 사용시간에 제한이 없음
    - 시간 제한이 없는 상태에서 빠른 배포를 위해 CI시간을 줄이는데 추가적인 작업을 진행해야할 필요를 못느낌
- v1은 기능이 간소
    - 프론트의 경우 정적 파일
    - ci에서 많은 시간이 걸리지 않을 것이라 가정
- 실제 CI 실행시간을 측정한 후 Build 시간이 개발 및 배포 속도에 영향을 주는 수준으로 증가하면 도입을 검토

⇒ 초기에는 파이프라인의 단순성을 우선시, 별도의 Cache 최적화 미적용

#### 3.2. feature → dev (PR)

- 기능의 변경사항을 dev branch에 통합하는 단계
- 기본적인 검증만 수행
    - 애플리케이션 빌드 가능 여부
    - 코드 규칙 검증
    - 라이브러리, 패키지 검사
- 실패시 Merge 차단

#### 3.3. dev → main (PR)

- main은 실제 배포의 기준이 되는 branch
- 해당 단계에서는 마지막으로 도커 이미지 빌드 가능여부 확인
    - 애플리케이션 빌드 가능 여부
    - 코드 규칙 검증
    - 라이브러리, 의존성 검사
    - 도커 이미지 빌드 가능 여부 확인
        - 배포 대상인 이미지만 레지스트리에서 관리하기 위해 최종 머지때 이미지 빌드 및 레지스트리에 푸시
- 실패시 Merge 차단

[ 2. 전체 CI흐름 ]

feature
   │
   │ PR
   ▼
┌─────────────────────────┐
│ CI                      │
│ Build / Compile         │
│ Lint                    │
│ Dependency              │
└───────────┬─────────────┘
            │ Success
            ▼
           dev
            │
            │ PR
            ▼
┌─────────────────────────┐
│ CI                      │
│ Build / Compile         │
│ Lint                    │
│ Dependency              │
│ Docker build            │
└───────────┬─────────────┘
            │ Success
            ▼
           main
            │
            │ Merge
            ▼
┌─────────────────────────┐
│ Image Build             │
│ Tag                     │
│ Commit SHA + 생성일     │
│ GHCR Push               │
└───────────┬─────────────┘
            │
            ▼
          GHCR
            │
            ├─ backend:a81c29f-20260905
            │
            └─ ai:921bf30-20260904

[ 3. 세부 도구 확정 ]

3.1. Build/compile검증 ⇒ Gradle

  • 현재 BE는 Spring boot + Gradle 기반
    • 별도의 빌드 도구 추가없이 Gradle을 사용
  • 검증의 이유
    • 변경된 코드의 정상적 컴파일 가능 여부 확인
    • 프로젝트 정상 빌드 가능 여부 확인
    • 의존성 문제로 인한 빌드 실패 여부 확인
    • 실행 가능한 jar 생성 가능 여부 확인
      • jar(자바 애플리케이션 실행 배포 위해 여러 파일을 하나로 묶은 파일 Java ARchive)

3.2. Lint ⇒ Spotbugs, Checkstyle

3.2.1. 린트란?

  • 정적 분석 도구 / 코드를 실행하지 않고 소스코드나 바이트 코드를 분석
  • 잠재적인 버그 가능성, 위험한 패턴, 스타일등의 문제 찾아내는 도구
  • 한계 : 실행 경로 알 수 없음, 런타임에 어떤 값 들어오는지 모름 → 실제 동작 기준의 검증은 불가

3.2.2. 도구 종류

  • 최소 CI 를 위한 목적이 분리된 2가지 도구
    • V1에서는 검사 범위 중복과 설정·관리 복잡도 증가를 고려하여 최소한의 정적 분석 도구만 적용
    • 코드의 복잡도, 패턴등을 분석하는 PMD나 별도의 분석환경, 퀄리티게이트가 필요한 SonarQube는 제외
도구 설치 위치목적
SpotBugs Gradle 플러그인 빌드/CI에서 버그 차단
Checkstyle Gradle 플러그인 스타일 규칙 강제
  • SpotBug
    • 빌드 도중 실행
      • 빌드 단계에서 다시 한번 코드를 검사해서 문제가 있으면 빌드를 실패시킴
      • 실제 사고로 이어지는 버그 패턴을 잡는데 집중된 도구
        • nullpointerexeption, == equals, 리소스 누수, 동시성 관련 문제등
  • checkstyle
    • 버그를 찾는 도구라기보다는, 코드 스타일 및 컨벤션을 검사하는 도구
      • 들여 쓰기, 중괄호, 네이밍 규칙, import 순서 등

3.3. Dependency ⇒ Github Dependency Review

3.3.1. Dependency 검사란?

  • 프로젝트에서 사용하는 외부 라이브러리 및 패키지의 의존성을 검사
  • 현재 사용하는 의존성 또는 새롭게 추가되는 의존성에 알려진 보안 취약점이 존재하는지 확인
  • 애플리케이션 코드 자체의 버그를 검사하는 Lint와는 검사 대상이 다름
    • Lint → 직접 작성한 코드의 문제 검사
    • Dependency 검사 → 프로젝트가 가져와 사용하는 외부 라이브러리의 문제 검사
  • 알려진 취약점 정보를 기반으로 검사하므로 아직 공개되거나 등록되지 않은 취약점은 탐지할 수 없음

3.3.2. 비교

기준 OWASP Dependency-Check GitHub Dependency Review
주요 검사 대상 프로젝트의 의존성 PR에서 추가/변경되는 의존성
검사 시점 Build / CI 실행 시 Pull Request
Gradle 설정 Plugin 설정 필요 필요 없음
GitHub Actions 연동 Gradle 명령을 통해 실행 Action 직접 사용
취약점 기준 공개 취약점 DB 기반 GitHub Advisory Database 기반
CI 실패 설정 가능 가능
별도 서버 필요 없음 필요 없음
관리 부담 상대적으로 존재 낮음
V1 PR Merge 차단 목적 가능 적합

3.3.3. 결정

현재 V1의 Dependency 검사의 주된 목적은 Dependency 전체에 대한 복잡한 보안 관리 체계를 구축하는 것이 아니라, 개발 과정에서 취약한 Dependency가 새롭게 추가되어 Merge되는 것을 사전에 차단하는 것

현재 CI 환경

  • GitHub Repository 사용
  • GitHub Actions 사용
  • feature → dev, dev → main의 PR 기반 Git Flow 사용
  • V1에서는 CI Pipeline의 단순성과 관리 부담 최소화를 우선
  • 별도의 Dependency 검사 서버 및 복잡한 보안 관리 기능을 요구하지 않음

[ 4. CI 실패 기준 확립 ]

  • Gradle

    ⇒ build,compile 실패시 merge 차단

  • checkstyle

    • ci결과에는 표시 (경고)
    • merge 차단은 안함
  • spotbugs

    • 버그 패턴 발견시 spotbugs가 bug rank 판단 → 1~20 존재
    • 1~4(scariest)부분만 merge 차단
  • github dependency review

    • severity 사용
    • github advisory database에 있는 취약점 정보를 활용하는데
      • 이 취약점 정보 → low, moderate, high, critical
      • 너무 낮은 레벨부터 막을 경우 낮은 위험도에도 개발이 막힘

    ⇒ High 이상의 Severity를 가진 취약점이 포함된 Dependency가 새롭게 추가될 경우 CI 실패

  • docker image build

    • 이미지 빌드 실패시 merge차단
    • github-hosted라 workflow 종료되면 만들었던 이미지도 같이 폐기됨
#CI
#해당 파이프라인은 PR때만 작동
name: KGB Backend CI

on:
  # feature -> dev / dev -> main PR
  pull_request:
    branches:
      - dev
      - main

permissions:
  contents: read
  # packages: write

jobs:

  # PR 검증
  # ==================================================
  pr-ci:
    name: PR CI
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest

    steps:

      # Repository Checkout
      - name: Checkout
        uses: actions/checkout@v4

      # JDK 설정
      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '21'

      # Gradle Wrapper 실행 권한
      - name: Grant Gradle Permission
        run: chmod +x gradlew

      # Build / Compile 검증
      # 실패 시 Merge 차단
      - name: Gradle Build
        run: ./gradlew build

      # Checkstyle
      # 위반 내용 표시
      # build.gradle의 ignoreFailures = true 적용
      # Merge 차단 X
      - name: Checkstyle
        run: ./gradlew checkstyleMain

      # SpotBugs
      # Rank 5~20 제외
      # Rank 1~4 발견 시 실패
      - name: SpotBugs
        run: ./gradlew spotbugsMain

      # Dependency Review
      # 새롭게 추가/변경된 Dependency 대상
      # High 이상 취약점 발견 시 실패
      - name: Dependency Review
        uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: high

      # Docker Image Build 검증
      # dev -> main PR에서만 실행
      # Image Push X
      - name: Docker Build Test
        if: github.base_ref == 'main'
        run: docker build -t backend:ci .