콘텐츠로 이동

SonarQube 정적 분석

원천 · framework/evomind/web/workflow-project-evo-service기준 · 릴리스 v0.12.0커밋 · 2e32c6cc파일 · docs/operations/sonarqube.md기준선 · 2026-11-12

사내 SonarQube 서버로 이 저장소의 코드(백엔드 Java·프론트 TypeScript)를 CI 에서 분석하고, 백엔드는 JaCoCo 커버리지까지 올린다. 지금은 결과를 알리기만 하고 파이프라인을 막지 않는다. 서버 주소와 토큰은 이 문서·저장소·이슈에 적지 않는다.

프로젝트(서버) 분석 방법 소스
evo-service-api Gradle 플러그인 org.sonarqube(backend/app/build.gradle.kts 의 sonar 블록) — 클래스패스를 알아 Java 분석이 정확하다 backend/app/src/main, 테스트 src/test, 커버리지 jacocoTestReport.xml
evo-service-web 스캐너 CLI(sonarsource/sonar-scanner-cli:12.3, frontend/sonar-project.properties) frontend/src(단위 테스트가 없어 커버리지는 올리지 않는다)
  • 두 프로젝트로 나눈 것은 Java 분석에 컴파일된 클래스와 의존성 클래스패스가 필요하기 때문이다(프론트는 빌드 없이 소스만 본다).
  • 백엔드 테스트가 끝나면 JaCoCo 0.8.16 이 backend/app/build/reports/jacoco/test/jacocoTestReport.xml 을 만든다(./gradlew build 에 포함). CI 의 backend_build 가 이 보고서를 아티팩트로 남기고 분석 job 이 읽는다(테스트를 다시 돌리지 않는다).
job 조건 동작
sonarqube_backend develop push, SONAR_HOST_URL·SONAR_TOKEN 이 있을 때 ./gradlew :app:sonar -x test
sonarqube_frontend 같음 sonar-scanner
  • MR 에서는 분석하지 않는다. SONAR_TOKEN 은 protected 변수라 보호되지 않은 브랜치·MR 파이프라인에 전달되지 않고, Community Build 는 브랜치 분석·GitLab MR 연동이 없는 것으로 알려져 있다. 병합 뒤 develop 분석 결과를 서버에서 본다. MR 분석이 필요해지면 서버 에디션(Developer 이상)과 토큰 전달 방식을 다시 정해야 한다.
  • 예약 파이프라인에서는 돌리지 않는다(코드가 바뀌지 않으면 결과가 같다).
  • job 은 allow_failure 이고 개발 러너(docker-build 태그,.101·.202)에서 돈다. 변수가 없으면 job 이 만들어지지 않고, 서버에 접속하지 못하면 job 만 실패하고 파이프라인은 계속된다.
  • 분석 job 은 GIT_DEPTH: "0"(전체 이력)으로 받는다. 얕은 클론이면 Shallow clone detected, no blame information 경고가 나고 소스 작성자 정보가 빠진다.
  • 품질 기준(Quality Gate)은 기다리지 않는다(-Dsonar.qualitygate.wait=false). 서버 화면에서 통과 여부를 본다.
  • SONAR_HOST_URL(일반)·SONAR_TOKEN(masked + protected, 분석 실행 전용 글로벌 토큰)은 최상위 그룹 framework·internal 의 CI/CD 변수로 등록되어 하위 프로젝트가 상속한다(evo-infra 가 등록). 스캐너는 두 값을 환경 변수로 읽으므로 명령줄·로그에 값이 나오지 않는다.
  • 이 저장소의 develop·main 은 보호 브랜치이고 릴리스 태그는 보호 태그가 아니다. 그래서 토큰은 develop 파이프라인에만 전달된다.
  • 토큰에는 만료일이 없다. 로그·아티팩트·이슈·MR 에 값을 찍지 않는다. 교체가 필요하면 evo-infra 에 요청한다.
  • 프로젝트 자동 생성은 evo-infra 도 확인하지 못했다. 첫 분석에서 “프로젝트가 없다”는 오류가 나면 SonarQube 에서 evo-service-api·evo-service-web 프로젝트를 만들고(키가 같아야 한다) 다시 돌린다. 안 만들어진 채 토큰 권한 부족이 원인이면 evo-infra 에 알린다.

  • 분석이 실패하면 job 로그의 마지막 오류 줄을 본다. 서버 접속 실패는 러너의 DNS·TLS 문제일 수 있다(개발 러너.101·.202 는 접속을 확인했다).

  • 로컬에서 분석 설정을 보려면 서버가 필요하다(스캐너 엔진을 서버에서 내려받는다). 로컬 시험은 cd backend && ./gradlew :app:test(JaCoCo 보고서 확인)까지만 한다.

  • 첫 분석(2026-10-30) 결과: 프로젝트 evo-service-web·evo-service-api 가 첫 분석으로 자동 생성됐고(토큰에 생성 권한 있음), TLS 는 추가 설정 없이 통과했다. 프론트 분석 12.6초, 백엔드 sonar 단계 약 55초. 경고: 얕은 클론(위 GIT_DEPTH), Java Unresolved imports/types(분석은 성공, 원인 미확인), 프론트 소스의 인코딩 경고 — 실제로 깨진 글자(U+FFFD)가 있어 로 고쳤다(경고를 그냥 넘기지 말고 파일을 열어 본다).

  • 서버 API 는 익명 접근을 막아 CI 밖에서 결과(커버리지 반영 등)는 서버 화면에서 로그인해 확인한다.

  • 서버 화면의 두 프로젝트에서 이슈(버그·취약점·코드 냄새)·보안 핫스팟·커버리지·중복을 본다.
  • 몇 번의 분석 결과를 본 뒤 품질 기준과 파이프라인을 막는 조건을 사용자가 정한다. 그 전에는 막지 않는다.
  • 라이브러리·이미지 취약점은 SonarQube 가 아니라 Trivy(docs/operations/vulnerability-scan.md)가 본다.