先日の記事に引き続き、セキュリティ関連のツールとなりますがSonarQubeを使ってみました。コードのバグ、セキュリティ脆弱性、コードの複雑さ、デッドコード、重複コードなど、幅広いコード品質の指標をチェックしてくれます。前回の記事同様Docker環境を利用していますので、前提事項などは前回記事をご確認ください。
前提
1. SonarQubeインストール
Dockerイメージを取得します。
docker pull sonarqube
以下の順にコマンドを実行して、コンテナ起動+スキャナーツールをコンテナにコピーします。
docker run -d --init --name sonarqube -e SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true -p 9000:9000 sonarqube:latest
wget https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-6.1.0.4477-linux-x64.zip
docker cp sonar-scanner-cli-6.1.0.4477-linux-x64.zip sonarqube:/tmp/
2. 事前準備
続いて、検査前の事前準備をします。
コンテナにログインして、パッケージインストールとスキャナーを解凍します。
docker exec -it -u root sonarqube /bin/bash
apt update
apt install vim unzip git
mv /tmp/sonar-scanner-cli-6.1.0.4477-linux-x64.zip ./
unzip sonar-scanner-cli-6.1.0.4477-linux-x64.zip
スキャナーを実行できるよう/root/.bashrcにパスを追加します。
export PATH="$PATH:/opt/sonarqube/sonar-scanner-6.1.0.4477-linux-x64/bin/"
追加したら反映させましょう。
source ~/.bashrc
3. プロジェクト作成
では検査対象のプログラムの準備およびGUIでの操作となります。
まずは、検査対象のプログラムを配置するためのディレクトリを作成します。
cd ..
mkdir sonar-test001
cd sonar-test001
git init
git initを実行しないとスキャナー実施時にエラーが出ますので実行しておきましょう。準備できたらこちらのディレクトリに以前利用したmain.pyのファイルを配置します。以下の記事のmain.pyを使っています。
続いてブラウザから操作します。アクセス用URLは http://ip:9000 となります。
ID/PASSはともにadminです。
ではプロジェクト作成に移ります。画面左したの「Create a local project」をクリックします。
プロジェクト名を入れます。ここではコンテナで作成したディレクトリ名を付けていますが、一意であれば何でもOKです。
「Use the global settings」を選択して「Create project」をクリックします。
画面が遷移します。画面左したの「Locally」をクリックします。
tokenIDが表示されます。「Continue」をクリックします。
言語はPythonなので、Otherを選択して、OSはLinuxを選択します。画面下にスキャナー実行用コマンドが表示されますので、「Copy」ボタンをクリックしておきましょう。
では、いよいよ検査実行です。コンソールに戻りコンテナ上で先ほどCopyしたコマンドを貼り付けて実行します。
実行ログ
02:38:39.106 INFO Scanner configuration file: /opt/sonarqube/sonar-scanner-6.1.0.4477-linux-x64/conf/sonar-scanner.properties
02:38:39.108 INFO Project root configuration file: NONE
02:38:39.116 INFO SonarScanner CLI 6.1.0.4477
02:38:39.117 INFO Java 17.0.11 Eclipse Adoptium (64-bit)
02:38:39.118 INFO Linux 3.10.0-1160.88.1.el7.x86_64 amd64
02:38:39.134 INFO User cache: /root/.sonar/cache
02:38:39.429 INFO JRE provisioning: os[linux], arch[x86_64]
02:38:39.479 INFO Communicating with SonarQube Server 10.6.0.92116
02:38:39.652 INFO Starting SonarScanner Engine...
02:38:39.653 INFO Java 17.0.11 Eclipse Adoptium (64-bit)
02:38:40.083 INFO Load global settings
02:38:40.124 INFO Load global settings (done) | time=42ms
02:38:40.126 INFO Server id: 147B411E-AZE06BXCv8WKtGkGQpv_
02:38:40.132 INFO Loading required plugins
02:38:40.132 INFO Load plugins index
02:38:40.141 INFO Load plugins index (done) | time=7ms
02:38:40.142 INFO Load/download plugins
02:38:40.170 INFO Load/download plugins (done) | time=30ms
02:38:40.329 INFO Process project properties
02:38:40.333 INFO Process project properties (done) | time=4ms
02:38:40.338 INFO Project key: sonar-test001
02:38:40.339 INFO Base dir: /opt/sonar-test001
02:38:40.339 INFO Working dir: /opt/sonar-test001/.scannerwork
02:38:40.343 INFO Load project settings for component key: 'sonar-test001'
02:38:40.353 INFO Load project settings for component key: 'sonar-test001' (done) | time=10ms
02:38:40.368 INFO Load quality profiles
02:38:40.404 INFO Load quality profiles (done) | time=36ms
02:38:40.426 INFO Load active rules
02:38:44.241 INFO Load active rules (done) | time=3816ms
02:38:44.244 INFO Load analysis cache
02:38:44.252 INFO Load analysis cache (4.0 kB) | time=8ms
02:38:44.285 INFO Preprocessing files...
02:38:44.325 INFO 1 language detected in 1 preprocessed file
02:38:44.325 INFO 0 files ignored because of scm ignore settings
02:38:44.327 INFO Loading plugins for detected languages
02:38:44.327 INFO Load/download plugins
02:38:44.327 INFO Load/download plugins (done) | time=0ms
02:38:44.353 INFO Load project repositories
02:38:44.366 INFO Load project repositories (done) | time=10ms
02:38:44.371 INFO Indexing files...
02:38:44.371 INFO Project configuration:
02:38:44.376 INFO 1 file indexed
02:38:44.377 INFO Quality profile for py: Sonar way
02:38:44.377 INFO ------------- Run sensors on module sonar-test001
02:38:44.406 INFO Load metrics repository
02:38:44.416 INFO Load metrics repository (done) | time=13ms
02:38:44.656 INFO Sensor Python Sensor [python]
02:38:44.657 WARN Your code is analyzed as compatible with all Python 3 versions by default. You can get a more precise analysis by setting the exact Python version in your configuration via the parameter "sonar.python.version"
02:38:44.753 INFO Starting global symbols computation
02:38:44.756 INFO 1 source file to be analyzed
02:38:44.873 INFO 1/1 source file has been analyzed
02:38:44.888 INFO Starting rules execution
02:38:44.889 INFO 1 source file to be analyzed
02:38:45.212 INFO 1/1 source file has been analyzed
02:38:45.213 INFO The Python analyzer was able to leverage cached data from previous analyses for 0 out of 1 files. These files were not parsed.
02:38:45.213 INFO Sensor Python Sensor [python] (done) | time=557ms
02:38:45.213 INFO Sensor Cobertura Sensor for Python coverage [python]
02:38:45.214 INFO Sensor Cobertura Sensor for Python coverage [python] (done) | time=2ms
02:38:45.214 INFO Sensor PythonXUnitSensor [python]
02:38:45.215 INFO Sensor PythonXUnitSensor [python] (done) | time=1ms
02:38:45.215 INFO Sensor JaCoCo XML Report Importer [jacoco]
02:38:45.216 INFO 'sonar.coverage.jacoco.xmlReportPaths' is not defined. Using default locations: target/site/jacoco/jacoco.xml,target/site/jacoco-it/jacoco.xml,build/reports/jacoco/test/jacocoTestReport.xml
02:38:45.216 INFO No report imported, no coverage information will be imported by JaCoCo XML Report Importer
02:38:45.216 INFO Sensor JaCoCo XML Report Importer [jacoco] (done) | time=1ms
02:38:45.217 INFO Sensor Java Config Sensor [iac]
02:38:45.219 INFO 0 source files to be analyzed
02:38:45.224 INFO 0/0 source files have been analyzed
02:38:45.224 INFO Sensor Java Config Sensor [iac] (done) | time=8ms
02:38:45.225 INFO Sensor IaC Docker Sensor [iac]
02:38:45.225 INFO 0 source files to be analyzed
02:38:45.259 INFO 0/0 source files have been analyzed
02:38:45.259 INFO Sensor IaC Docker Sensor [iac] (done) | time=34ms
02:38:45.259 INFO Sensor TextAndSecretsSensor [text]
02:38:45.259 INFO Available processors: 8
02:38:45.259 INFO Using 8 threads for analysis.
02:38:45.472 INFO The property "sonar.tests" is not set. To improve the analysis accuracy, we categorize a file as a test file if any of the following is true:
* The filename starts with "test"
* The filename contains "test." or "tests."
* Any directory in the file path is named: "doc", "docs", "test" or "tests"
* Any directory in the file path has a name ending in "test" or "tests"
02:38:45.481 INFO Using git CLI to retrieve untracked files
02:38:45.487 INFO Analyzing language associated files and files included via "sonar.text.inclusions" that are tracked by git
02:38:45.487 INFO Sensor TextAndSecretsSensor [text] (done) | time=229ms
02:38:45.489 INFO ------------- Run sensors on project
02:38:45.502 INFO Sensor Zero Coverage Sensor
02:38:45.506 INFO Sensor Zero Coverage Sensor (done) | time=4ms
02:38:45.507 INFO SCM Publisher SCM provider for this project is: git
02:38:45.507 INFO SCM Publisher 1 source file to be analyzed
02:38:45.615 WARN Could not find HEAD commit
02:38:45.624 INFO SCM Publisher 0/1 source files have been analyzed (done) | time=117ms
02:38:45.625 WARN Missing blame information for the following files:
02:38:45.625 WARN * main.py
02:38:45.625 WARN This may lead to missing/broken features in SonarQube
02:38:45.626 INFO CPD Executor Calculating CPD for 1 file
02:38:45.630 INFO CPD Executor CPD calculation finished (done) | time=3ms
02:38:45.671 INFO Analysis report generated in 36ms, dir size=207.4 kB
02:38:45.679 INFO Analysis report compressed in 8ms, zip size=27.3 kB
02:38:45.696 INFO Analysis report uploaded in 16ms
02:38:45.697 INFO ANALYSIS SUCCESSFUL, you can find the results at: http://10.2.0.50:9000/dashboard?id=sonar-test001
02:38:45.697 INFO Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
02:38:45.697 INFO More about the report processing at http://10.2.0.50:9000/api/ce/task?id=8adb9e52-ffc7-4f93-9919-8667b31d4ba2
02:38:45.701 INFO Analysis total time: 5.507 s
02:38:45.702 INFO SonarScanner Engine completed successfully
02:38:45.728 INFO EXECUTION SUCCESS
02:38:45.729 INFO Total time: 6.624s
しばらくするとSonarQubeの画面が遷移して結果が表示されます。
前回の記事で諸々修正していたので、何も指摘がありませんでしたので、以下のReactコードを試してみました。
1 Open issuesと表示されていますので、こちらをクリックします。
レンダリングに関する内容で問題がるようです。「Why is this an issue?」をクリックします。
一意の識別子でないとパフォーマンスに問題が出る可能性ありとの指摘みたいです。
回避策も記載ありますので、これにならってコードを変更してみます。
{rankings.map((ranking) => (
<Card key={ranking.combined_text} style={{ marginBottom: '1rem' }}>
combined_textはmain.py(get_rankings関数)のリターン部分の第1カラムとなります。
rankings = [{"combined_text": s[0], "summary": s[1], "count": s[2]} for s in sorted_summaries]
すべてクリアになりました!Activityにも反映されています。
4. その他
前回はおもにPython関連のツールでしたが、SonarQubeは様々な言語に対応しているようなので個人で利用するには十分なツールだと思いました。