SonarQube Cloud + GitHub Actions でGitHub リポジトリを連携しMaven プロジェクトの静的コード解析をする
今回は静的コード解析ツールのSonarQube Cloud とGitHub Actions を使い、リポジトリへのPush 時にMaven プロジェクトの静的コード解析を行います。
実施環境
Java | Microsoft OpenJDK 21.05 |
---|
前提条件
- GitHub のアカウントおよびコード解析用のリポジトリがあること
SonarQube とは
概要
SonarQube はSonarSource が提供している様々なプログラミング言語やフレームワーク、IaC プラットフォームの静的コード解析を行うツールです。幅広いプログラミング言語やIaC ツール、Dockerfile などの定義ファイルをサポートしており、WebUI を利用した品質、セキュリティ、カバレッジの確認を行える特徴があります。また、各種CI ツールと連携することにより、リポジトリへのPush やコードレビュー (Pull Request) 時にコードの連携を行うことができます。SonarQube を利用するには以下の方法があります。
- サーバー、VM にSonarQube を導入する
- SonarQube のコンテナイメージを起動する
- SonarQube Cloud を利用する
ユーザー側でサーバーリソースがある場合はサーバー、VM にSonarQube サーバーを導入することで利用できます。コンテナイメージの場合、ホスト上にコンテナを起動させる、Kubernetes 上にSonarQube のコンテナを起動する方法があります。
SonarQube はビルド時やコマンドの実行時に実行されます。ビルドファイルや設定ファイルにSonarQube のサーバーまたはSonarQube Cloud を指定したり、ビルドコマンドで指定する方法があります。この仕様からSonarQube を利用するにはビルドやCI/CD のパイプラインを実行するホストからSonarQube の実行環境に接続できる必要があります。
SonarQube の自己管理型にはいくつかプランがあります。本記事はSonarQube Cloud を中心としているため、プランごとの機能の違いや料金は以下ページを確認してください。
SonarQube Plans & Pricing | Sonar
SonarQube Cloud
SonarQube Cloud はSonarSource がホストの運用・管理を行っているマネージドのサービスです。ホスト側の管理が不要となるため、SonarQube ホストの運用・管理コストを削減できます。基本的な機能は自己管理型のSonarQube と同じです。
SonarQube Cloud はFree、Team、Enterprise のプランがあります。プランごとに利用できる機能の違いは以下となります。
Free | Team | Enterprise | |
---|---|---|---|
利用用途 | 個人向け、検証用 | 小規模チーム向け、 | 大規模向け、ミッションクリティカル、スケーラビリティが必要 |
ユーザー | 5ユーザーまで | 無制限 | 無制限 |
言語とフレームワーク | 30 | 30 | 36 (Team プランにABAP、APEX、COBOL、JCL、PL/I、RPG が追加) |
プライベートリポジトリのスキャン | 50k 行まで | 100k 行まで | 無制限 |
ブランチ、Pull Request | Main ブランチおよびPull Request で利用可能 | Main およびその他ブランチ、Pull Request で利用可能 | Main およびその他ブランチ、Pull Request で利用可能 |
AI コード修正 | 無し | 利用可能 | 利用可能 |
AI コード保証 | 無し | 利用可能 | 利用可能 |
SSO | 無し | 無し | 利用可能 |
商用サポート | 無し | 利用可能 | 利用可能 |
エンタープライズ SLA | 無し | 無し | 有り |
SonarQube Cloud のその他プランごとの機能、料金は以下URL を参照してください。
Plans & Pricing SonarQube Server and SonarQube Cloud Developer Tools | Sonar
今回の構成
今回はSonarQube Cloud のFree プランで登録し、GitHub の特定のリポジトリにあるMaven プロジェクトのコード解析を行うところまで実施します。
SonarQube Cloud への登録
初めにSonarQube Cloud にFree プランで登録します。SonarQube Cloud のトップページから Start now を選択します。
GitHub と連携するため、GITHUB を選択します。
Import an organization を選択し、GitHub アカウントと認証します。
認証後、SonarQube Cloud で分析するリポジトリを選択します。全てのリポジトリを対象とする場合は All repositories を選択し、特定のリポジトリのみ分析する場合は Only select repositories からリポジトリを選択します。画像はテスト用のリポジトリ・sonarqubetest を指定しています。リポジトリ選択後は Install を選択します。
リポジトリ指定後、SonarQube の組織を作成します。組織名とキーの指定が必要となるため任意の値を指定します。画像では組織名をYoung Leaves、キーを young-leaves で設定しています。
組織設定後、下にスクロールしプランを設定します。今回はFree プランで作成するため、 Free プランの Select Free を選択し Create Organization で組織を作成します。
組織作成後、管理画面に遷移されたら登録完了です。
新規プロジェクト作成、GitHub リポジトリへの連携
SonarQube Cloud 登録後、新規プロジェクトとGitHub の接続用シークレット作成を行います。SonarQube ではプロジェクト単位でコードを分析するためプロジェクトの作成は必須となります。初めにAnalyze a new project からプロジェクトを作成します。
次にコード分析を行うGitHub リポジトリを選択し Setup を選択します。
次にコード分析時の新しいコードを定義します。Previous version は以前のバージョンから変更されたコード全てを新しいコードを分析対象とみなします。Number of days は指定した日数以内に変更された新しいコードを分析対象とみなします。今回は Previous version を選択し Create project を選択します。
プロジェクト作成後、プロジェクトの管理画面およびサマリが表示されます。
左ペインから Main ブランチ、Pull Request、その他Branch の状況を確認できます。今回はFree プランのためMain ブランチの情報のみとなりますが、開発環境やステージング環境など他の環境でもSonarQube の実行結果を確認したい場合、各項目から実行結果を確認してください。
プロジェクト作成後、GitHub Actions 用のシークレットを準備します。管理画面の左ペインから Administration > Analisys Method を選択します。GitHub Actions を利用するため、Automatic Analysis を無効にし、With GitHub Actions を選択します。
GitHub シークレットの作成方法とトークが表示されるため、GitHub の対象リポジトリから Setting > Secrets and variables > Actions から Repository secrets を作成します。
シークレット名は SONAR_TOKEN、値はトークンを設定します。設定後、Add secret でシークレットを作成します。
Maven プロジェクト、GitHub Actions ワークフローの作成
プロジェクトとGitHub シークレットの準備後、テスト用のJava コードとビルドファイル (pom.xml)、GitHub Actions ワークフローファイルを作成します。今回作成するファイルのフォルダ構成は以下となります。Git の初期設定は省略するため各自で実施してください。
.
├── .github
│ └── workflows
│ └── build.yaml
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── org
│ │ └── example
│ │ └── Main.java
│ └── resources
└── test
└── java
Java のコードは以下のとおりです。今回はSonarQube で意図的に脆弱性を発生させるため、OS コマンドインジェクションとデバッグメッセージを公開する可能性のあるコードを意図的に用意しています。そのため、このコードを参考とした実装は行わないようにしてください。
package org.example;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
String dir = "user_input"; // ユーザー入力
try {
Process process = Runtime.getRuntime().exec("ls " + dir);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
次にMaven 用のpom.xml ファイルを準備します。SonarQube でビルド時にチェックするためにはpom.xml ファイルのproperties で sonar.organization に組織のキー、sonar.host.url にSonarQube Cloud のURL を設定します。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>testmaven</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.organization>[組織のキー]</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
</properties>
</project>
pom.xml 準備後、GitHub Actions のワークフローファイルを作成します。SonarQube Cloud 用のワークフローファイルは管理ページの Administration > Analisys Method よりGitHub Actions 選択後にMaven を選択するとテンプレートが表示されます。デフォルトではJDK のバージョンが17、Zulu OpenJDK を利用しているため、こちらをMicrosoft JDK 21 に修正します。
name: SonarQube
on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build and analyze
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK 21 # 17から21に修正
uses: actions/setup-java@v4
with:
java-version: 21 # 17から21に修正
distribution: 'microsoft' # zuluからmicrosoftに修正
- name: Cache SonarQube packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=kdkwakaba_sonarqubetest
リポジトリへのPush、コード分析結果の確認
Java ファイル、pom.xml、GitHub Actions ワークフローファイルの準備後、該当コードをGitHub リポジトリにPush します。Push 後、自動でGitHub Actions が実行されるためワークフローの実行結果が成功することを確認します。
ワークフロー成功後、SonarQube Cloud のMain Branch より実行結果を確認します。今回は意図的に脆弱性を入れているため、Security Hotspots を満たしていないことで失敗となっています。
実行結果にはNew Code とOverall Code の2種類があります。新しいコードの実行結果はNew Code、過去の実行結果を含めたものはOverall Code で確認できます。New Code では New Issue (新たに発見された問題)、Accepted Issue (カバレッジから除外する問題)、Coverage (テストカバレッジ)、Duplications (コードの重複率)、Security Hotspots (セキュリティの脆弱性) が表示されます。Overall Code ではSecurity、Reliability (信頼性)、Maintainability (保守性)、Accepted Issue、Coverage、Duplications、Security Hotspots が表示されます。
コード分析で発見された内容は Issue タブより確認できます。exec とデバッグメッセージについてチェックがされています。
Security Hotspots タブではコード分析で発見された脆弱性が表示されます。コードのどの部分に脆弱性があるか表示されるため、こちらを参考にコードを修正します。
Measure タブでは各項目に対する測定内容を確認できます。コードの分析結果をグラフで確認できるため、コードの品質を可視化できます。
Code タブでは各コードにおける項目ごとの数および割合を確認できます。どのコードの品質が低いかを可視化できます。
Active タブではコード分析の実行状況を確認できます。
まとめ
- SonarQube はプログラム言語、IaC ツール、各種定義ファイルの脆弱性やコードの不備などをチェックする静的コード解析ツール
- SonarQube Cloud を利用することでホスト側の運用・管理工数の削減ができる
- SonarQube Cloud はビルド時に静的コード解析を実施し、各種CI ツールでも利用可能