OpenShift PipelineでSonarQubeによるソースコードスキャンのタスクを追加する

# はじめに
- 本記事では以下の流れを説明します。
    - 既にOpenShiftのクラスタ内にDeployされているSonarQubeと、アプリケーションのソースコードが格納されているGitHubのリポジトリを接続する
    - Soner-Scanタスク（SonerQubeによるソースコードスキャンを行うタスク）をTekton (OpenShift Pipelines)に追加する

# この記事を書いた理由
- 何気に今からやろうとしている事を一から解説してくれている情報が無かったので、今後同じことをやる人の参考にしようと思ったから。
- あと自分の備忘録

# 事前準備①： 
- OpenShift上に既存のPipelineがDeployされている。
- 今回利用するサンプルアプリをSource to Image（S2I）にてDeployした際に自動的に作られるPipelineをカスタマイズする格好で、SonarQubeによるソースコード解析Taskを追加してみます。

## ご参考：S2IによるアプリケーションDeploy時にPipelineを自動で生成する方法
- 適当な`NameSpace`において「+追加」 -> 「Gitからのインポート」と進みます
- GitリポジトリのClone URLをコピペします
![スクリーンショット 2023-12-08 14.21.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/e1ce9315-cf86-2000-5ecc-6b0ca3635749.png)
    - [log-test](https://github.com/masaki-oomura/log-test)というNode.jsのアプリを作ったのですが、これでやっていきます。
    - 文字列を入力して`Submit`をクリックすると、標準出力に文字列をログとして出すだけのなんてこと無いアプリでして、作り方は殆どChatGPTに聞きました。
- S2IのPipelineを生成するのは超簡単です。ここにチェックを入れて「作成」をクリックするだけです。
![スクリーンショット 2023-12-08 14.25.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/d6767d8b-661b-8295-224b-ec4bbecc18da.png)
- 「表示パイプラインの可視化」を押すと簡単なTaskの構成順序を見れます。
![スクリーンショット 2023-12-08 14.28.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/4584dad9-3f84-5085-ddc5-835351171ecd.png)
    - `fechrepository`：ソースコード一式をリポジトリからClone（ダウンロード）してくる
    - `build`：コンテナイメージをBuildをする
    - `deploy`：コンテナとしてDeployする
- 作成するとこんな感じで「パイプライン」が作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/698b7ea7-efe9-40ad-2905-2bb56fdb6362.png)
- ちなみに、この手法でアプリケーションをDployすると、同じ`NameSpace`に`el-event-listener-hogehoge`というDeploymentがApplyされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c2b794d6-cb05-abb2-b116-de527c53f8c6.png)
- こいつは何か？ということなのですが、`EventListener`はGitリポジトリからのWebhook通知を受け、それを元にTektonに対して「Gitリポジトリの中身更新されたっぽいんで、Pipelineブン回してもらっていいすかね？」っていう指示を飛ばすPodになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/84c787ea-8b2e-8cb5-4a4d-d9d15ac04204.png)
- ちゃちゃっとGitHubのリポジトリのWebhook機能を設定してみます。
- 任意のリポジトリの「Setteings」タブをクリックしてください
![スクリーンショット 2023-12-14 15.19.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/525f4e1b-e9c1-5fe8-b8c2-52bdfc14f078.png)
- 「Setteings」メニュー左側の「Webhook」をクリックしてください
![スクリーンショット 2023-12-14 15.20.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b0904a5c-a44d-a899-4f22-b2843b741e84.png)
- 「Add Webhook」をクリックしてください
![スクリーンショット 2023-12-14 15.21.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/bc94d75e-d761-3db8-8139-7ae157fff188.png)
- 最低限、以下の様にパラメータを設定してみます。
    - `Payload URL`: EventListenerのRoute(URL)を入れる。このURLにWebhookを飛ばしてくれます。
    - `Content type`: `application/json`を選択してください。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/fa3e6c73-57cf-1332-1c66-bc22f417c358.png)
- 「Add Webhook」をクリックしてWebhook連携が完了します。


# 事前準備②： OpenShiftにSonarQubeをDeployする
- 既に公開済みの[こちらの記事](https://qiita.com/masaki-oomura/items/53d3d88b5314c18fdb9a)をご参照ください。
- 以下はSonarQubeのコンソール画面にログインができたあとからの流れで説明します。



# SonerQubeとGitHubを接続する
- 基本的には[SonarQubeの公式サイト](https://docs.sonarsource.com/sonarqube/9.8/devops-platform-integration/github-integration/)を参考にして、Step1,2,3と進めていけば大丈夫です。
- 要所だけかいつまんで見ていきます。
## GitHub Appを作成して、自身のOrgにinstallする
- インテグレーションの為のGitHub Appsを作成します。
- GitHub Appを作成すると、以下の様なパラメータが払い出されます。
    - `GitHub App ID`
    - `Client ID`
    - `Client Secret`: 今作ったGitHub Appのページで生成します
    - `Private Key`: 同じく、今作ったGitHub Appのページ(一番下までスクロール)で生成します
- [こちら](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app)に従って、自身のOrg（もしOrgに所属しない場合は自身のアカウントIDがそれにあたります）にAppをInstallしましょう。
## SonarQubeにGitHub Appのパラメータを入力する
- SonarQubeに初めてログインした場合、Project作成画面に居ると思います。
- 今回は`Import from GitHub`から、各種パラメータを入力しましょう
![スクリーンショット 2023-12-07 18.08.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/a73d837a-3aab-481c-d28b-4c47f4165d10.png)
- GitHub App作成時に生成される種々のパラメータを入力してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/082579da-0f03-7714-364a-20da8ea941c4.png)
- 連携がうまくいくと、リポジトリ選択画面が出ますので、連携したいリポジトリ（＝アプリケーション）を`Import`します
    - GitHub Appをご自身のOrg（あるいはアカウント）にInstallしていない場合、エラー出ますので、[こちら](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app)に従って忘れずにInstallしてください。
- 私は [log-test](https://github.com/masaki-oomura/log-test)のリポジトリを指定しました。ご自身のスキャンしたいソースコード格納先をご指定ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b1460428-6829-9052-af56-13de847f3de5.png)
- `Import`できると、`Analysis Method`の画面に行きます。
- ここで、各種のCIツールと連携することになるのですが、Tekton (OpenShift Pipelines)はデフォルト選択肢に無いので、`Other CI`を選んでください。
![スクリーンショット 2023-12-07 18.15.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/0d91e8fb-d6fc-abcf-e46e-1c0f11099507.png)
- ここまででGitHubの特定のリポジトリと、OpenShiftにDeployしたSonarQubeとの連携までできました。
- いよいよここからはPipelineのTaskにSonarQubeによるソースコード解析をTaskとして追加する作業に進みます

# Pipelineにソースコード解析をTaskとして追加する
- ちょっと頭の整理をします
    - `完了`: ~~[こちらの記事](https://qiita.com/masaki-oomura/items/53d3d88b5314c18fdb9a)に従いSonarQubeをOpenShiftにDeployした~~
    - `完了`: ~~GitHub Appを介してSonarQubeとGitHubを連携した~~
    - `これから`: SonarQubeによるソースコード解析Taskを作成する
    - `これから`: Tekton(OpenShift Pipeline）に当該Taskを追加する
- もうちょいです。頑張りましょう！
## SonarQube側でToken生成する
- 前の画面で`Other CI`をクリックすると、Token生成画面に遷移します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/75ecbdde-4333-ceb9-1983-d655fa116dfe.png)
- ここでTokenの情報を設定して`Generate`をクリックしてください。
- Tokenの破棄期間（Expireタイム)はご自由にどうぞ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/d36c1df0-9725-d4e9-7a98-fc54db96ef2a.png)
- `Continue`を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b56f1bf9-3ee9-f357-40e0-dad40679e8a6.png)
- アプリケーションのフレームワーク選択画面が出てきますので、該当するものを選択してください。
- 今回はNode.jsのアプリケーションですので、`Other`を選択しました
![スクリーンショット 2023-12-07 18.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b66295d6-50d6-9a40-67e1-5d9c50a753e1.png)
- すると`SONAR_TOKEN`とかいうパラメータが生成されます。
- こいつがTektonがSonarQubeのProjectにアクセスするために必要な認証情報になるわけです。
- 他にも色々スニペットが生成されているのですが、一旦無視でOkです。

## Tekton (OpenShift Pipeline)のPipelineにTaskを追加する
- SonarQubeの画面は閉じずに、OpenShiftのコンソールに戻りましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/c016995e-2a79-402e-9728-43f65b6ac002.png)
- こちらはトポロジーの画面なのですが、一旦わかりやすいように、SonarQubeがDeployされている`NameSpace`と同じ所に、`log-test`アプリもDeployしちゃいました。
- もちろん、アプリケーションは別に`NameSpace`を作ってDeployしておいてもOKです。
- この`log-test`アプリのPipelineはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/58ad0358-5096-b680-9fe9-837f6b50142c.png)
- このPipelineにSonarQubeによるソースコード解析Taskを追加しましょう！
- Pipeline詳細画面の右上「アクション」 -> 「パイプラインの編集」へ進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/655b1af9-2a1e-4694-fb84-826380b55285.png)
- ソースコード解析のTaskですから、PipelineのWorkspace（※）にソースコードをCloneしてきた直後、つまり`fechrepository`と`build`の間にTaskとして追加する必要がありますね。
    - (※)Pipelineを実行中のみ`PersistentVolume`がマウントされて立ち上がる作業スペース。ここで一旦ソースコードや設定ファイルなどを作成したり、スクリプト実行をしたりしてTaskが実行される
![スクリーンショット 2023-12-08 14.44.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/0ce16a49-2559-06ba-cced-4c1fcd7f4269.png)
- この辺にマウスオーバーすると`+`ボタンが出るんで、クリック。
- 「Taskの追加」をクリックすると、Task検索画面が出てくるので、`sonar`と入れると`sonar-scanner`というTaskが出てきます。
    - こちらは[TektonHub](https://hub.tekton.dev/)にて公開されている[SonarQubeによるソースコード解析Task](https://hub.tekton.dev/tekton/Task/sonarqube-scanner/0.2)です。
    - 「みんなこういうTask要るやろ？」というのはだいたいTektonHubに公開されています。
- ここでver1.0かver2.0を選択してInstallしてください。
    - Ver3.0移行はSonarQubeのSaaS版との連携に必要なパラメータ指定が必要なのですが、今回はSelf-Install版を使っているので、1.0か2.0でやってください。
    - 私は一旦2.0のほうでやっていきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/45f74199-622e-a200-1c6b-08c932a6dfab.png)
- Taskが追加されました。ここからパラメータを追加していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/0697e0c2-5c82-e487-6a3c-73bc50699a47.png)
- なお、デフォルトのパラメータについて説明します
## デフォルトのパラメータ
- `SONAR_HOST_URL`: http://”アプリ名”.”NameSpace名”.svc.cluster.local:9000
    - こいつはCluster内からのアクセス先URLを指定します。
    - TektonはOpenShiftのClusterの中に居ますので、インターネットからのアクセス先URL（＝RouteのURL）ではなく、ホスト名指定でも良いわけです。
    - ホスト名は`Service`リソースの画面で見れます
 ![スクリーンショット 2023-12-08 15.01.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b785ab18-3f95-fcd6-e483-7436213ada3d.png)
    - `Service`名をクリックして、
![スクリーンショット 2023-12-08 15.03.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/4be3e8fe-cac5-03de-cc1f-53f3d3eb48d4.png)
    - 頭に`http://`を付けて、ExposeしているPort番号（=9000番）をくっつければOK
    - つまり私の場合は http://docker-sonarqube.sonarqube.svc.cluster.local:9000 となります。繰り返しますが、こちらのURLはインターネットからはアクセスできません。
- `SONAR_PROJECT_KEY`: SonarQubeの画面で確認可能
![スクリーンショット 2023-12-07 18.23.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/4dc94b26-35ca-c7c5-ed32-868a2e64b909.png)
## デフォルトのパラメータを入力してTaskをRunしてみる
- 結論から言うとエラーが起きます。
- まぁまずはやってみましょう。
- TektonのPipeline編集画面に戻ってください。デフォルトのパラメータ入力欄に値を入力します。
    - `SONAR_HOST_URL`:上述の通り
    - `SONAR_PROJECT_KEY`:上述の通り
    - `source`: スキャンするべきソースコードをCloneしてきた`Workspace`名を指定します。既に「workspace」という名前のそれがあるので選択します。
    - `sonar-settings`: SonarQubeによるスキャン実行TaskがPodとして起動する為に必要な設定情報です。Taskの中で自動生成されます。こちらも「workspace」を設定しておいてOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/80abd8df-94e5-b8a4-1468-c170893c8750.png)
- 「保存」をクリックします。
- 右上の「アクション」 -> 「開始」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/767b3ec9-1f49-34fb-4e5c-77a0c87ee565.png)
- ここまでの操作でPipeline実行の為に必要なパラメータが設定されているはずですので、「開始」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/43e87b86-4899-9389-9024-63de37ba5658.png)
- 当初想定通り、`SonarQube-Scanner`Taskでエラーが起きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b6b3f9c6-fe44-a94d-2757-61d86826411f.png)
- 「ログ」からエラーメッセージを見てみます。要は「認証できません」ということらしいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/bbf28089-ca23-d8f7-4a89-c3c35b5109e6.png)
- そうです！`SONAR_TOKEN`を設定していませんね！
- `Sonar-Scanner`Taskの.yamlファイルを修正して、`SONAR_TOKEN`パラメータを設定しましょう。

## Sonar-ScannerにSONAR_TOKEN情報を設定できるようにする
- Pipeline詳細画面に戻って、`sonarqube-scanner`Taskをクリックします。
![スクリーンショット 2023-12-14 15.50.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/de6ba31f-e6c3-b852-e13b-95b6e8892f87.png)
- 「YAML」タブに遷移し、以下の様に追記します。

```yaml:spec.params
- default: ''
  description: Token information
  name: SONAR_TOKEN
  type: string
```
![スクリーンショット 2023-12-14 15.54.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/110ebb0e-36f3-df49-e1a4-0e78b42c9cdf.png)

```sh:spec.steps
echo "sonar.token=$(params.SONAR_TOKEN)" >> sonar-project.properties
```
![スクリーンショット 2023-12-14 16.08.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/5725b9d8-8a2b-760d-47b7-550f11d969c3.png)
- 「保存」を押してYamlファイルの編集を反映しましょう。
- 再びPipeline編集画面に戻ってください
![スクリーンショット 2023-12-14 16.10.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/b7fd68ea-6117-8b17-d4ba-1d182627efde.png)
- 「sonarqube-scanner」Taskをクリックすると、`SONAR_TOKEN`欄が増えています！
![スクリーンショット 2023-12-14 16.12.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/5325bf7e-df72-e9fd-23e1-c6f767387e83.png)
- SonarQubeの画面で確認できる`SONAR_TOKEN`の値をコピペして、「保存」をクリックしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/5fbe269a-0d18-9f0d-f969-5b32020e96b3.png)
- もう一回Pipeline実行を開始してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/29a0acb7-0a4d-8c0e-1479-112f94424cdc.png)
- 無事Pipeline実行が成功しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/8d81d37d-da4a-bc98-b242-5e586f2288fe.png)
- SonarQubeのProject画面を確認するとスキャン結果を確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3627586/a9af4788-9549-09d1-bc34-79b5350feb46.png)
# 最後に
- これでSonarQubeによるソースコードスキャンTaskが追加できました。