SonarQube（Java）の、ルールの出典を確認したい

# Whats'？

SonarQubeで使えるJavaのルールって、SonarQube自身が提供しているのか、それとも他のOSSなどのルールを使っているのか知りたいなぁと思いまして。


# 結論

すべて、SonarQube自前のルールでした。

SpotBugs、FindSecBugs、PMD、Checkstyleで検出した問題については、インポートが可能だということです。

[Importing Third-Party Issues](https://docs.sonarqube.org/latest/analysis/external-issues/)

> SonarQube doesn't run your external analyzers or generate reports. It only imports pre-generated reports.

[Importing SpotBugs, FindSecBugs, PMD, Checkstyle Issues Reports（※このページはもうメンテナンスされていません）](https://docs.sonarqube.org/pages/viewpage.action?pageId=11639185)  

今回は、その確認の過程を書いていきます。


# 環境

今回は、SonarQubeサーバー 8.6 Community Editionを対象とします。


# SonarQubeで使えるJavaのルール

SonarQubeサーバーで「Rules」から「Java」を選ぶと、Javaに関するルールが605あることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/87d1cda2-e37e-6b24-cfa2-2d50110775eb.png)

なんとなく、ドキュメントを見るとSpotBugs、FindBugs、FindSecBugs、PMD、Checkstyleが関係していそうな気はします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/f9e5e339-84bb-33c7-bc4e-34b89b097e5f.png)

External Issues、とは書いていますが…。

[Analyzing Source Code / Languages / Java](https://docs.sonarqube.org/8.6/analysis/languages/java/)

[Java / Related Pages](https://docs.sonarqube.org/8.6/analysis/languages/java/#header-6)

SonarQube上で見てみても、関係しているのかどうかわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/0ef573fb-076b-f404-3e57-69447126a822.png)

個別のルールを見ても、やっぱりわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/6bb5c3fe-9aaa-2acd-35f5-380e7e7614b1.png)

分類として、Code Smell、Bug、Vulnerability、Security Hotspotがあるのはわかるんですけどね。

[Rules](https://docs.sonarqube.org/8.6/user-guide/rules/)


# Sonar Maven Pluginを見る

こちらのエントリで少し使ってみたので、Sonar Maven Pluginを起点に追ってみましょう。

[MavenプロジェクトでSonarQubeを使ってみる](https://qiita.com/charon/items/3a85397652532a0fda20)

[SonarScanner for Maven](https://docs.sonarqube.org/8.6/analysis/scan/sonarscanner-for-maven/)

現時点のSonar Maven Pluginの`pom.xml`などを見ても、SpotBugsなどが入っている様子はありません。

https://github.com/SonarSource/sonar-scanner-maven/blob/3.8.0.2131/pom.xml

どうやら、クライアント側は関係ないようです。


# Sonar Java Pluginを見る

いろいろ調べていると、こちらが実体のように思います。

[Code Quality and Security for Java](https://github.com/SonarSource/sonar-java)

ここで、SonarQubeサーバーのインストールディレクトリにある、`lib/extensions`ディレクトリを見てみます。

ちょっと気になります。

```shell
$ ll lib/extensions
-rw-r--r--. 1 xxxxx xxxxx  5056472 Dec  9 10:25 sonar-csharp-plugin-8.15.0.24505.jar
-rw-r--r--. 1 xxxxx xxxxx 10627704 Dec  9 10:25 sonar-css-plugin-1.3.1.1642.jar
-rw-r--r--. 1 xxxxx xxxxx  1550044 Dec  9 10:25 sonar-flex-plugin-2.6.0.2294.jar
-rw-r--r--. 1 xxxxx xxxxx  6102054 Dec  9 10:25 sonar-go-plugin-1.8.1.1804.jar
-rw-r--r--. 1 xxxxx xxxxx   823033 Dec  9 10:25 sonar-html-plugin-3.3.0.2534.jar
-rw-r--r--. 1 xxxxx xxxxx    19648 Dec  9 10:25 sonar-jacoco-plugin-1.1.0.898.jar
-rw-r--r--. 1 xxxxx xxxxx 18717478 Dec  9 10:25 sonar-java-plugin-6.9.0.23563.jar
-rw-r--r--. 1 xxxxx xxxxx 19371396 Dec  9 10:25 sonar-javascript-plugin-7.0.1.14561.jar
-rw-r--r--. 1 xxxxx xxxxx  8466805 Dec  9 10:25 sonar-kotlin-plugin-1.8.1.1804.jar
-rw-r--r--. 1 xxxxx xxxxx  5310930 Dec  9 10:25 sonar-php-plugin-3.13.0.6849.jar
-rw-r--r--. 1 xxxxx xxxxx  4527459 Dec  9 10:25 sonar-python-plugin-3.1.0.7619.jar
-rw-r--r--. 1 xxxxx xxxxx 13053290 Dec  9 10:25 sonar-ruby-plugin-1.8.1.1804.jar
-rw-r--r--. 1 xxxxx xxxxx 14687152 Dec  9 10:25 sonar-scala-plugin-1.8.1.1804.jar
-rw-r--r--. 1 xxxxx xxxxx  3760426 Dec  9 10:25 sonar-vbnet-plugin-8.15.0.24505.jar
-rw-r--r--. 1 xxxxx xxxxx  2242738 Dec  9 10:25 sonar-xml-plugin-2.0.1.2020.jar
```

Community Editionを使っているので、ちょうどサポート対象の15言語分ですね。

SonarQubeサーバーのドキュメントを見ていると、解析はクライアント側でやっているのかな？と思うのですが、

[Install the Server](https://docs.sonarqube.org/8.6/setup/install-server/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/4b226bdc-7fa1-5b85-8ad3-5a7a95fdf8c8.png)

適用するルールはサーバー側で管理しているので、ちょっとわからなくなりますね。

`sonar-java-plugin-6.9.0.23563.jar`は、こちらのリポジトリから作られたもののようです。

[Code Quality and Security for Java](https://github.com/SonarSource/sonar-java)

ちょっと中身を見てみましょう。

```shell
$ jar -tvf lib/extensions/sonar-java-plugin-6.9.0.23563.jar | grep -iE 'spotbugs|findbugs|findsecbugs|pmd|checkstyle'
  1626 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/checks/NoCheckstyleTagPresenceCheck.class
  1587 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/checks/NoPmdTagPresenceCheck.class
  4548 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/PmdSensor.class
  6057 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/CheckstyleXmlReportReader.class
  9209 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/PmdXmlReportReader.class
  5807 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/SpotBugsSensor.class
   511 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/CheckstyleXmlReportReader$IssueConsumer.class
  9549 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/SpotBugsXmlReportReader.class
     0 Mon Oct 05 01:32:58 UTC 2020 org/sonar/l10n/java/rules/spotbugs/
 24823 Mon Oct 05 01:32:06 UTC 2020 org/sonar/l10n/java/rules/spotbugs/findsecbugs-rules.json
 76105 Mon Oct 05 01:32:06 UTC 2020 org/sonar/l10n/java/rules/spotbugs/fbcontrib-rules.json
     0 Mon Oct 05 01:32:58 UTC 2020 org/sonar/l10n/java/rules/checkstyle/
 34405 Mon Oct 05 01:32:06 UTC 2020 org/sonar/l10n/java/rules/checkstyle/rules.json
  5829 Mon Oct 05 01:32:58 UTC 2020 org/sonar/java/externalreport/CheckstyleSensor.class
     0 Mon Oct 05 01:32:58 UTC 2020 org/sonar/l10n/java/rules/pmd/
 61670 Mon Oct 05 01:32:06 UTC 2020 org/sonar/l10n/java/rules/pmd/rules.json
130757 Mon Oct 05 01:32:06 UTC 2020 org/sonar/l10n/java/rules/spotbugs/spotbugs-rules.json
     0 Mon Oct 05 01:32:58 UTC 2020 META-INF/maven/com.google.code.findbugs/
     0 Mon Oct 05 01:32:58 UTC 2020 META-INF/maven/com.google.code.findbugs/jsr305/
  4286 Fri Mar 31 10:21:36 UTC 2017 META-INF/maven/com.google.code.findbugs/jsr305/pom.xml
   121 Fri Mar 31 10:55:32 UTC 2017 META-INF/maven/com.google.code.findbugs/jsr305/pom.properties
```

少し関係ありそうですね。

たとえば、こちら。

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/external-reports/src/main/resources/org/sonar/l10n/java/rules/spotbugs/spotbugs-rules.json

抜粋してみます。

```json
[
  {
    "key": "AM_CREATES_EMPTY_JAR_FILE_ENTRY",
    "name": "Bad practice - Creates an empty jar file entry",
    "type": "CODE_SMELL",
    "severity": "MAJOR",
    "url": "https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html#AM_CREATES_EMPTY_JAR_FILE_ENTRY"
  },
  {
    "key": "AM_CREATES_EMPTY_ZIP_FILE_ENTRY",
    "name": "Bad practice - Creates an empty zip file entry",
    "type": "CODE_SMELL",
    "severity": "MAJOR",
    "url": "https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html#AM_CREATES_EMPTY_ZIP_FILE_ENTRY"
  },
  {
    "key": "AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION",
    "name": "Multi-threading - Sequence of calls to concurrent abstraction may not be atomic",
    "type": "BUG",
    "severity": "MAJOR",
    "url": "https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html#AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION"
  },

...

]
```

`type`とルール上の分類が一致しそうですね。

リポジトリを`clone`して中身を見てみます。

```shell
$ git clone https://github.com/SonarSource/sonar-java.git
$ cd sonar-java
```

対象のバージョンに`checkout`。

```shell
$ git checkout 6.9.0.23563
```

`type`で集計してみます。

```shell
$ find external-reports/src/main/resources/org/sonar/l10n/java/rules -name '*.json' | xargs grep '"type"' | perl -wp -e 's!.+("type.+)!$1!' | sort | uniq -c
    553 "type": "BUG",
    654 "type": "CODE_SMELL",
    139 "type": "VULNERABILITY",
```

多い…。

ファイルパスも一部含めてみましょう。

```shell
$ find external-reports/src/main/resources/org/sonar/l10n/java/rules -name '*.json' | xargs grep '"type"' | perl -wp -e 's!.+/(.+/.+) *("type.+)!$1 $2!' | sort | uniq -c
    156 checkstyle/rules.json:     "type": "CODE_SMELL",
    288 pmd/rules.json:     "type": "CODE_SMELL",
    308 spotbugs/fbcontrib-rules.json:     "type": "BUG",
    128 spotbugs/findsecbugs-rules.json:     "type": "VULNERABILITY",
    245 spotbugs/spotbugs-rules.json:     "type": "BUG",
    210 spotbugs/spotbugs-rules.json:     "type": "CODE_SMELL",
     11 spotbugs/spotbugs-rules.json:     "type": "VULNERABILITY",
```

うーん、よくわからないですね…。

実際にSonarQubeサーバーが認識しているルールは、ここにあるようです。

https://github.com/SonarSource/sonar-java/tree/6.9.0.23563/java-checks/src/main/resources/org/sonar/l10n/java/rules/java

Sonar wayプロファイルの定義もありました。

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/java-checks/src/main/resources/org/sonar/l10n/java/rules/java/Sonar_way_profile.json

なんですけど、全然わからない名前が並んでいます。

```json
{
  "name": "Sonar way",
  "ruleKeys": [
    "S100",
    "S101",
    "S106",
    "S107",
    "S108",
    "S110",
    "S112",
    "S114",

...
```

このディレクトリ内にあるファイルのほとんどは、自動生成されたもののようです。

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/java-checks/src/main/resources/org/sonar/l10n/java/rules/java/README.md

実体は、同じプロジェクトのこういうコードでしょうか？

```java
@DeprecatedRuleKey(ruleKey = "S00100", repositoryKey = "squid")
@Rule(key = "S100")
public class BadMethodNameCheck extends IssuableSubscriptionVisitor {
```

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/java-checks/src/main/java/org/sonar/java/checks/naming/BadMethodNameCheck.java#L34

`S[数字]`なものを確認してみましょう。

```shell
$ grep -rE '"S[0-9]+"' java-checks/src/main/java | perl -wp -e 's!.+(S\d+).+!$1!' | sort -u | wc -l
599
```

599個ですね。

ここで、SonarQubeのルールを"リポジトリ"という単位別に見れることに気づいたので、見比べてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/c09575db-5179-9702-055a-bc2a31e5205f.png)

「SonarQube」が599個。一致します。

つまり、ここにあるのがSonarQubeのルールの実体です。

https://github.com/SonarSource/sonar-java/tree/6.9.0.23563/java-checks/src/main/java/org/sonar/java/checks

残りの6個はというと、こちらに定義してあります。

https://github.com/SonarSource/sonarqube/blob/8.6.0.39681/server/sonar-webserver-core/src/main/java/org/sonar/server/rule/CommonRuleDefinitionsImpl.java

つまり、605個のルールはすべてSonarQube自前のルールでした。

ここでこのページに気づき、あくまでSpotBugs、FindSecBugs、PMD、Checkstyleは「インポート可能なもの」だと認識しました…。

[Importing SpotBugs, FindSecBugs, PMD, Checkstyle Issues Reports](https://docs.sonarqube.org/pages/viewpage.action?pageId=11639185)

なるほど、それで"External Issues"だったんですね。

こちらのページで、インポートするファイルのパスをシステムプロパティで指定できると書いていますが、それが書いてあるのがここですね。

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/external-reports/src/main/java/org/sonar/java/externalreport/SpotBugsSensor.java#L50

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/external-reports/src/main/java/org/sonar/java/externalreport/PmdSensor.java#L38

https://github.com/SonarSource/sonar-java/blob/6.9.0.23563/external-reports/src/main/java/org/sonar/java/externalreport/CheckstyleSensor.java#L43

なるほど、すっきりしました。