GitHub에 올려둔 프로젝트와 SonarCloud를 연결해서 소스코드 정적 분석을 해보자.

정적 분석은 소스 코드 품질을 높이기 위해 잠재적인 버그나, 코딩 컨벤션에 어긋나는 부분을 찾아내는 것을 의미한다.

 

대표적인 정적 분석 툴은 SonarQube다. SonarQube는 사용하려면 직접 웹서버에 세팅을 해서 돌려야 하는데, 동일 개발사에서 만든 SonarCloud라는 클라우드 서비스를 사용하면 개인 서버를 준비하는 것보다 훨씬 편리하게 정적 분석을 해볼 수 있다.

 

SonarCloud와 GitHub 연결하기

먼저 링크에 들어가서 회원가입을 하자.

로그인을 하고 나면 아래와 같은 화면으로 이동한다.

처음으로 사용해보는 거라면 Import projects from GitHub를 클릭한다.

내 GitHub에서 SonarCloud를 설치할 레포지토리를 선택한다.

직접 선택해도 되고, 모든 레포에 접근 권한을 줄 수도 있다.

 

Install을 누르면 organization 생성 화면으로 이동하게 된다.

여기서 organization 전용 key를 만들어야 하는데, 나중에 GitHub에서 SonarCloud를 연결할 때 사용하게 된다.

organization에서 사용할 plan(무료 or 유료)을 선택해야 한다.

public access 프로젝트면 기능을 무료로 사용할 수 있고, 나는 토이 프로젝트에 써보는 거라 Free Plan을 선택했다.

Create Organization을 클릭하고, 정적 분석을 실행할 레포를 체크하고 Set up을 누르면 끝난다.

그럼 이렇게 대시보드 형태로 내 프로젝트 현황을 볼 수 있다.

분석 카테고리는 크게 Bugs, Vulnerabilities, Code Smells, Duplications인데.. 내가 시험 삼아 연결해본 프로젝트들은 아직 코드가 얼마 없어서 지적된 내용이 별로 없다.

 

Rules 탭에 들어오면 언어별로 정적 분석기가 찾아낼 Rule을 관리할 수 있다.

지원하는 언어가 다양하고 Java는 562개, Kotlin의 경우 49개의 규칙이 built-in으로 등록되어 있다. 여기서 rule 추가, 삭제 등을 할 수 있는데 여럿이서 작업할 경우 사전에 협의해둔 컨벤션을 추가해두면 규칙에 어긋나는 코드를 편하게 찾을 수 있을 것 같다.

 

프로젝트를 클릭해보면 더 상세한 분석 결과를 볼 수 있다.

어떤 파일의 어떤 line에 문제가 있는지 디테일하게 가이드를 준다. 나같은 경우 별생각 없이 ip 주소를 하드코딩해놓은걸 고치라고 보안 경고가 하나 떴다.

 

참고 : Free Plan 사용 시 SonaCloud 분석 결과 페이지는 링크만 있으면 누구나 열람할 수 있게 된다. 물론 코드가 이미 github에 공개되어 있지만, 내 코드의 취약점을 따로 보기 좋게 모아서 볼 수 있는 페이지를 모두에게 오픈(?)해주는 셈이니 그러면 안되는 상황이라면 이점 유의하길 바란다.

 

이제 SornalCloud가 설치된 레포에서 Automatic Analysis가 자동으로 on 돼서 PR이 열릴때마다 정적 분석 실행 결과가 코멘트로 달린다. 한번씩 들어가서 내가 실수한 게 있나 살펴보면 좋을 것 같다.

 

만약 Automatic Analysis를 비활성화 하고 싶다면 Administration > Analysis Method에서 Automatic Analysis를 off로 돌리면 된다.

 

 


+α : CI-based Analysis 설정하기 (GitHub Action으로 SonarCloud 실행하기)

정적 분석 실행 타이밍을 CI와 연결해서 바꾸고 싶은게 아니면 여기부턴 안봐도 무방함

 

더 찾아보니까 GitHub Action으로도 SonarCloud를 사용할 수 있길래 한번 해봤다. (GitHub Action에 대한 간단한 소개는 내 예전 글을 참고하면 된다.) 가이드를 참고하니 방법이 어렵지 않았다.

 

* 참고로 GitHub Action으로 설정하는 CI-based Analysis는 Automatic Analysis랑 같이 실행하면 충돌이 나므로, 쓰고 싶으면 둘 중 하나는 반드시 비활성화 해야한다.

 

프로젝트 대시보드 우측 하단에 보면 이렇게 project key랑 아까 만들었던 organization key가 나온다.

 

 

레포 root 경로에 .sonarcloud.properties라는 이름으로 파일을 하나 만든다. 이 파일에는 위에서 언급한 key와 분석할 소스 코드가 위치한 경로를 선언해주면 된다. 프로젝트 전체를 분석하기 위해 경로명을 .으로 작성했다.

sonar.organization=<organization key>
sonar.projectKey=<project key>

sonar.sources=.

이제 Actions > New workflow를 클릭해서 GitHub Action이 실행할 workflow를 작성한다.

파일은 .yml 확장자로 저장해야 한다. 아래 스크립트는 Pull request가 열렸을 때마다 정적 분석이 돌아가게 하는 스크립트다.

on:
  pull_request:
      types: [opened, synchronize, reopened]

name: SonarCloud Scan

jobs:
  sonarcloud:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: SonarCloud Scan
      uses: sonarsource/sonarcloud-github-action@master
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

 

job에 선언된 내용을 살펴보면 GITHUB_TOKEN, SONAR_TOKEN으로 두 개의 secret value가 설정된 것을 볼 수 있다.

  • GITHUB_TOKEN : GitHub에서 알아서 만들어주는 인증 토큰이다. (참고 링크)
  • SONAR_TOKEN : SonarCloud에 접근 인증을 받기 위해 필요한 인증 토큰이다. SonarCloud에서 토큰을 생성한 후 레포지토리에 환경 변수로 등록해놔야 쓸 수 있다.

 

SONAR_TOKEN 등록하기

SonarCloud의 Security 페이지에 들어가서 토큰을 생성한다. 토큰 이름을 입력하고, Generate를 클릭하면 토큰 문자열이 나타나는데 복사하면 된다.

 

다시 GitHub로 돌아와서 SonarCloud가 연결된 레포의 Settings > Secrets에 들어가면 환경 변수를 설정할 수 있다.

Add a new secret을 클릭하자.

 

Name은 SONAR_TOKEN으로, Value로 아까 복사해 놓은 토큰 값을 붙여 넣기 하자.

환경 변수까지 설정하면 연결 끝이다. 이제 workflow에서 설정한 이벤트가 발생할 때마다 SonarCloud가 실행된다.

 

+α : GitHub Action + Maven 환경에서 SonarCloud 실행하기

sonarsource/sonarcloud-github-action@master를 사용했을 때, 만약 프로젝트 빌드 환경이 Gradle / Maven이면 아래와 같은 오류가 출력되면서 실행이 실패한다.

 

Do not use this GitHub action if you are in the following situations

  • Maven의 경우 → Your code is built with Maven: run 'org.sonarsource.scanner.maven:sonar' during the build
  • Gradle의 경우 → Your code is built with Gradle: use the SonarQube plugin for Gradle during the build

Gradle은 아예 SonarQube plugin을 쓰라고 나오는걸 보니 CI-based Analysis가 안되는 것 같고, Maven은 workflow에서 실행할 명령어를 바꿔야 한다. maven 명령어로 SonarCloud를 실행할 수 있는데, 이때 properties로 project key + organizatoin key + 위에서 만들었던 SONAR_TOKEN을 전달해야 한다.

 

먼저 CI 서버에 maven이 설치되어있지 않아도 maven을 사용할 수 있게 maven wrapper를 설치한다.

mvn -N io.takari:maven:wrapper -e 

 

github action으로 아래 명령어를 실행하도록 하면 된다!

./mvnw -B verify sonar:sonar \
   -Dsonar.projectKey=<projectKey> \
   -Dsonar.organization=<organizationKey> \
   -Dsonar.host.url=https://sonarcloud.io \
   -Dsonar.login= <sonarcloud key>

 

maven에서 CI-based Analysis로 SonarCloud를 실행하는 workflow 작성 예시다.

on:
  push:
    branches: 
      - master
  pull_request:
      types: [opened, synchronize, reopened]

name: SonarCloud Scan

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Set Up JDK
      uses: actions/setup-java@v1
      with:
        java-version: '11'
    - name: Run SonarCloud
      run: ./mvnw -B verify sonar:sonar -Dsonar.projectKey=zion830_sonar-cloud-test -Dsonar.organization=zion830-sonar-cloud-key -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

 

참고 자료