SonarQubeを利用してみた。

先日の記事に引き続き、セキュリティ関連のツールとなりますがSonarQubeを使ってみました。コードのバグ、セキュリティ脆弱性、コードの複雑さ、デッドコード、重複コードなど、幅広いコード品質の指標をチェックしてくれます。前回の記事同様Docker環境を利用していますので、前提事項などは前回記事をご確認ください。

# 前提

https://qiita.com/nw-engineer/items/306ca8e4b5b636e90920


# 1. SonarQubeインストール
Dockerイメージを取得します。
```bash
docker pull sonarqube
```
以下の順にコマンドを実行して、コンテナ起動＋スキャナーツールをコンテナにコピーします。
```bash
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. 事前準備
続いて、検査前の事前準備をします。
コンテナにログインして、パッケージインストールとスキャナーを解凍します。
```bash
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にパスを追加します。
```bash:.bashrc
export PATH="$PATH:/opt/sonarqube/sonar-scanner-6.1.0.4477-linux-x64/bin/"
```

追加したら反映させましょう。
```bash
source ~/.bashrc
```

# 3. プロジェクト作成
では検査対象のプログラムの準備およびGUIでの操作となります。
まずは、検査対象のプログラムを配置するためのディレクトリを作成します。
```bash
cd ..
mkdir sonar-test001
cd sonar-test001
git init
```

git initを実行しないとスキャナー実施時にエラーが出ますので実行しておきましょう。準備できたらこちらのディレクトリに以前利用したmain.pyのファイルを配置します。以下の記事のmain.pyを使っています。

https://qiita.com/nw-engineer/items/2eb58b07b16937e32fbc#2-fastapi%E6%BA%96%E5%82%99


続いてブラウザから操作します。アクセス用URLは *http://ip:9000* となります。
ID/PASSはともにadminです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/042b961d-e103-0625-d943-57c7a6b14173.png)

パスワードを変更しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/0b1c676f-a013-6cf3-d63d-e8d4e8272720.png)

ではプロジェクト作成に移ります。画面左したの「Create a local project」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/62ca4d62-608b-a60c-926c-0207948749c7.png)

プロジェクト名を入れます。ここではコンテナで作成したディレクトリ名を付けていますが、一意であれば何でもOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/a88dee28-2e44-f79e-adca-f67dae177c7c.png)

「Use the global settings」を選択して「Create project」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/c58fdccd-0b50-01a3-c774-c9daf046229c.png)

画面が遷移します。画面左したの「Locally」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/ee47b0c6-106e-b82e-69a7-1ff180095a26.png)

「Generate」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/0b82e0cb-8a90-8487-76a4-8c636cb6b873.png)

tokenIDが表示されます。「Continue」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/7c4412e4-a81f-7180-cfc2-cfa53cd5e305.png)

言語はPythonなので、Otherを選択して、OSはLinuxを選択します。画面下にスキャナー実行用コマンドが表示されますので、「Copy」ボタンをクリックしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/6991935f-0251-053c-cf60-43fcad3ad1b5.png)


では、いよいよ検査実行です。コンソールに戻りコンテナ上で先ほどCopyしたコマンドを貼り付けて実行します。

**実行ログ**
```bash
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の画面が遷移して結果が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/7b327c9b-3fa5-83fd-d9f6-eae107eb739f.png)



前回の記事で諸々修正していたので、何も指摘がありませんでしたので、以下のReactコードを試してみました。

https://qiita.com/nw-engineer/items/2eb58b07b16937e32fbc#4-react%E3%82%B3%E3%83%BC%E3%83%89%E4%BD%9C%E6%88%90

**1 Open issues**と表示されていますので、こちらをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/9aab5216-b8b4-a635-0695-b2f7bba4e3ce.png)

レンダリングに関する内容で問題がるようです。「Why is this an issue?」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/78647ff8-4a63-1ba4-a778-d643438743fb.png)

一意の識別子でないとパフォーマンスに問題が出る可能性ありとの指摘みたいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/63422645-efb6-b872-e2b0-4e2ec182c979.png)

回避策も記載ありますので、これにならってコードを変更してみます。
```react
  {rankings.map((ranking) => (
    <Card key={ranking.combined_text} style={{ marginBottom: '1rem' }}>
```

combined_textはmain.py(get_rankings関数)のリターン部分の第1カラムとなります。
```python
  rankings = [{"combined_text": s[0], "summary": s[1], "count": s[2]} for s in sorted_summaries]
```

すべてクリアになりました！Activityにも反映されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2335933/2bc69495-785d-35d5-aacb-62ef3f2c65e6.png)


# 4. その他
前回はおもにPython関連のツールでしたが、SonarQubeは様々な言語に対応しているようなので個人で利用するには十分なツールだと思いました。