# GitLab

本チュートリアルでは、Shisho Cloud 上のワークフローを GitLab リポジトリにインポートしたのち、リポジトリ内のワークフローと Shisho Cloud 上のワークフローを同期する仕組みを GitLab の CI/CD を用いて構築します。

本チュートリアルは、以下の 4 ステップからなります:

1. Shisho Cloud 上のワークフローを格納した GitLab プロジェクトを作成する
1. Shisho Cloud において、特定プロジェクトの CI/CD からのアクセスを許可する
1. GitLab において、ワークフローを Shisho Cloud にデプロイする CI/CD のジョブを作成する
1. GitLab において、リポジトリ内と Shisho Cloud 上のワークフローの差分をチェックする GitLab CI/CD のジョブを作成する

3\. のステップによって、リポジトリ内のワークフローの変更が即座に Shisho Cloud に反映されるようになります。
また 4\. のステップによって、Shisho Cloud の Web インターフェースから直接ワークフローを編集した場合に、その変更に対応するマージリクエストが作成されるようになります。
これらのセットアップによって、GitLab リポジトリと Shisho Cloud 上のワークフローが常に同期されるようになります。

:::info
GitLab CI/CD から Shisho Cloud にアクセスするために「Shisho Cloud のアクセストークンを GitLab CI/CD にシークレットとして登録する」というような操作の必要はありません。その代わりに、CI/CD のジョブに対して GitLab が発行する OIDC トークンの情報に基づき、Shisho Cloud がジョブに短命の認証情報を発行します。
:::

## ワークフローを格納した GitLab プロジェクトを作成する

Shisho Cloud 上の全ての検査ルールを Git でバージョン管理するために、まずは既に Shisho Cloud 上にあるワークフローをエクスポートして、リポジトリに取り込みましょう。

まず GitLab で新規プロジェクトを作成し、リポジトリをクローンしてください。クローンしたディレクトリへ Shisho Cloud 上のワークフローをエクスポートするには、次のコマンドを実行します。ただし、コマンド中の `$SHISHO_CLOUD_ORG_ID` はお使いの Shisho Cloud 組織の ID に置換してください。

```
shishoctl workflow export --structured --org $SHISHO_CLOUD_ORG_ID --path .
```

エクスポートが完了したら、作成されたファイルをコミットして GitLab にプッシュしてください。

## 特定プロジェクトの CI/CD から Shisho Cloud 組織へのアクセスを許可する

続いて、GitLab CI/CD から Shisho Cloud にログインできるよう、Shisho Cloud 側の設定をしていきます。まず Shisho Cloud の[ボット作成画面](https://cloud.shisho.dev/*/settings/bots)を開き、「ボット」を作成します。ボットとは Shisho Cloud 組織へのアクセス権限を持つ主体であり、GitLab のジョブはボットとして Shisho Cloud にログインすることになります。

![ボット作成画面](/docs/ja/_md-assets/709014004f-create-bot.png)

ボットを作成したら、ボット名をクリックすると信頼条件の設定画面に遷移します。

![信頼条件の設定画面](/docs/ja/_md-assets/947bafca52-create-trust-condition.png)

「プロバイダー」 は 「GitLab CI/CD」 を選択すると、GitLab の信頼条件が入力できるようになります。

![GitLabの信頼条件の設定画面](/docs/ja/_md-assets/4baca61d5c-create-gitlab-trust-condition.png)

信頼条件とは、GitLab のジョブが当該ボットとして Shisho Cloud にログインするために、ジョブが満たすべき条件です。ワークフローが格納されている GitLab プロジェクトのパスを記入すると、当該プロジェクトに属するジョブが、先ほど作成したボットとして Shisho Cloud にログインできるようになります。

:::info
信頼条件は GitLab の場合、プロジェクトパスの一致が条件となります。プロジェクトのパスは GitLab プロジェクトを特定する URL のグループ名から始まりプロジェクト名で終わるパスのことを指します。

ブラウザで GitLab のプロジェクトページを開くと URL が以下の形式となります:

```
https://gitlab.com/[グループ名]/[プロジェクト名]
```

サブグループを含む場合はサブグループ名が間に入ります:

```
https://gitlab.com/[グループ名]/[サブグループ01]/[サブグループ02]/　...　/[プロジェクト名]
```

これらのグループ名から始まりプロジェクト名で終わるパスの部分がプロジェクトパスに当たります:

```
[グループ名]/[サブグループ01]/[サブグループ02]/　...　/[プロジェクト名]
```

例えば、以下のプロジェクトページの URL があるとすると、太文字の部分がプロジェクトパスとなります。

- https​://gitlab.com/**my-group/my-project**
- https​://gitlab.com/**my-group/my-subgroup01/my-project**
- https​://gitlab.com/**my-group/my-subgroup01/my-subgroup02/my-project**

:::warning
GitLab ではグループ、サブグループ、プロジェクトの名前とは異なる文字列を URL のパスとして設定することが可能です。必ず GitLab プロジェクトの URL に使われているパスを確認してください。

ブラウザでプロジェクト配下の他のページを開いた場合（リポジトリのページなど）その別のページの情報もパスに含まるのでご注意ください。
:::

記入が完了したら、「保存」ボタンをクリックしてください。

## ワークフローを Shisho Cloud にデプロイする GitLab CI/CD ジョブを作成する

次のステップとして、ワークフローを Shisho Cloud にデプロイする GitLab CI/CD ジョブを作成しましょう。リポジトリ内に、以下のようなファイルを作成してください。

```yaml title=".gitlab-ci.yml"
include:
  - local: /.gitlab/jobs/shishocloud-workflows-deploy.yml
```

```yaml title=".gitlab/jobs/shishocloud-workflows-deploy.yml"
shishocloud-workflows-deploy-job:
  variables:
    # FIXME: お使いの Shisho Cloud 組織の ID に置換してください
    SHISHOCLOUD_ORG: flatt-security
    # FIXME: 入力すべき BOT_ID の値は信頼条件の設定画面に記載されています
    SHISHOCLOUD_BOT_ID: BTXXXXXXXXXXXXXXXXXXXXXXXXXX

  id_tokens:
    # Shisho Cloud にログインするために必要な権限
    ID_TOKEN:
      aud: https://gitlab.com

  script:
    # Install shishoctl
    - SHISHOCTL_URL="https://shisho.dev/releases/shishoctl-0.15.0-x86_64-unknown-linux-gnu"
    - curl -L $SHISHOCTL_URL -o /usr/local/bin/shishoctl
    - chmod +x /usr/local/bin/shishoctl

    # Sign in (as bot)
    - shishoctl auth signin:bot
      --bot ${SHISHOCLOUD_BOT_ID}
      --expires-in-minutes 60
      <<< ${ID_TOKEN}

    # Deploy workflows
    - shishoctl workflow apply --org "${SHISHOCLOUD_ORG}" --path .
```

コード中の `FIXME` と記載された箇所を適切に書き換えてください。なお、入力すべき `bot` の値は、先ほど作成した信頼条件の設定画面下部に記載されています。

![信頼条件の設定画面下部には、bot-id の値が記載されています](/docs/ja/_md-assets/5f294a47c5-gitlab_ci_step_example.png)

以上のようにしてファイルを作成したら、コミットして GitLab にプッシュしてください。

ここまでの設定により、`main` ブランチにプッシュされるたびにリポジトリ内のワークフローが Shisho Cloud にデプロイされるようになります。GitLab のプロジェクトページから「ビルド」>「パイプライン」を開き、ジョブが正常に実行されたことを確認しましょう。

## リポジトリ内と Shisho Cloud 上のワークフローの差分をチェックする GitLab CI/CD ジョブを作成する

これまでのセットアップによって、デフォルトブランチにプッシュされるたびにワークフローが Shisho Cloud にデプロイされるようになりました。しかし Shisho Cloud の Web インターフェースから直接ワークフローを編集した場合、リポジトリ内のワークフローと Shisho Cloud 上のワークフローとの間に差分が生じてしまいます。GitLab リポジトリで管理しているワークフローと Shisho Cloud 上で実際に実行されているワークフローが同一である状態を維持するためには、この 2 つの差分を定期的にチェックする必要があります。

`shishoctl workflow pull` コマンドは、Shisho Cloud 上のワークフローをローカルに取り込むコマンドです。このコマンドを利用して、Shisho Cloud 上のワークフローとリポジトリ内のワークフローとの間に差分がある場合に自動でマージリクエストを作成するジョブを作成していきます。

GitLab CI/CD のジョブ内でブランチをプッシュするためには、プッシュする権限があるプロジェクトのアクセストークンをまず作成する必要があります。GitLab のプロジェクトページから「設定」>「アクセストークン」を開き、「新しいトークンを追加」をクリックしてください。

![GitLab のアクセストークンの画面](/docs/ja/_md-assets/7184a7ef0b-access-tokens.png)

「プロジェクトのアクセストークンの追加」のページを開きますと以下の内容を入力してください:

|                     |                             |
| ------------------- | --------------------------- |
| **トークン名:**     | `Access token`              |
| **有効期限:**       | 任意                        |
| **ロールを選択:**   | `Developer`                 |
| **スコープを選択:** | `write_repository` のみ選択 |

![GitLab のアクセストークンの作成画面](/docs/ja/_md-assets/35f9eb17f2-create-access-token.png)

「プロジェクトのアクセストークンを作成」をクリックすると、作成されたトークンが表示されます。作成されたトークンをコピーしてください。

次に、CI/CD のジョブからトークンをアクセスできるように CI/CD で利用できる変数として設定する必要があります。GitLab のプロジェクトページから「設定」> 「CI/CD」を開き、「変数」を展開したら「変数を追加」をクリックしてください。

![GitLab の CI/CD の変数の画面](/docs/ja/_md-assets/5bbf66784c-cicd-variables.png)

「変数を追加」を開きますと以下の内容を入力してください:

|                 |                                      |
| --------------- | ------------------------------------ |
| **タイプ:**     | `変数`                               |
| **環境:**       | `すべて`                             |
| **Visibility:** | `マスク`                             |
| **フラグ:**     | 全て選択                             |
| **キー:**       | `ACCESS_TOKEN`                       |
| **値:**         | コピーしたアクセストークンを貼り付け |

![GitLab の CI/CD の変数の設定画面](/docs/ja/_md-assets/51f2c36acd-add-cicd-variable.png)

「変数を追加」をクリックすると、変数の設定が完了になります。これでジョブからは `ACCESS_TOKEN` の変数が参照できるようになりました。

次に、以下のようなジョブを作成します。`.gitlab-ci.yml` は新しいジョブの実行も含むよう更新します。今回のジョブはパイプラインスケジュールがトリガーとなるため、実行の条件も追加します。

```yaml title=".gitlab-ci.yml"
include:
  - local: /.gitlab/jobs/shishocloud-workflows-deploy.yml
    rules:
      - if: '$CI_PIPELINE_SOURCE != "schedule"'
  - local: /.gitlab/jobs/shishocloud-workflows-diff-check.yml
    rules:
      - if: '$CI_PIPELINE_SOURCE == "schedule"'
```

```yaml title=".gitlab/jobs/shishocloud-workflows-diff-check.yml"
shishocloud-workflows-diff-check-job:
  variables:
    # FIXME: お使いの Shisho Cloud 組織の ID に置換してください
    SHISHOCLOUD_ORG: flatt-security
    # FIXME: 入力すべき BOT_ID の値は信頼条件の設定画面に記載されています
    SHISHOCLOUD_BOT_ID: BTXXXXXXXXXXXXXXXXXXXXXXXXXX
    MR_TITLE: "Workflows on Shisho Cloud has changed"
    MR_DESCRIPTION: 'The workflows on Shisho Cloud has changed from those in this repository.\n\n> This PR was automatically created by the job `${CI_JOB_NAME}` in `${CI_CONFIG_PATH}`.'

  id_tokens:
    ID_TOKEN:
      aud: https://gitlab.com

  script:
    # Install shishoctl
    - SHISHOCTL_URL="https://shisho.dev/releases/shishoctl-0.15.0-x86_64-unknown-linux-gnu"
    - curl -L $SHISHOCTL_URL -o /usr/local/bin/shishoctl
    - chmod +x /usr/local/bin/shishoctl

    # Sign in (as bot)
    - shishoctl auth signin:bot
      --bot ${SHISHOCLOUD_BOT_ID}
      --expires-in-minutes 60
      <<< ${ID_TOKEN}

    # Pull workflows from Shisho Cloud, exit if no diff
    - shishoctl workflow pull --org "${SHISHOCLOUD_ORG}" --path . --structured
    - if [[ `git status --porcelain` == "" ]]; then echo "No diff between Shisho Cloud and this repository" && exit 0; fi

    # Commit changes and push
    - git remote add gitlab_origin ${CI_SERVER_PROTOCOL}://access_token:${ACCESS_TOKEN}@${CI_SERVER_FQDN}/${CI_PROJECT_PATH}.git
    - git config user.name "${GITLAB_USER_NAME}"
    - git config user.email "${GITLAB_USER_EMAIL}"

    - git checkout -b shisho-cloud-workflow-diff-`date +'%Y%m%d%H%M%S'`
    - git add .
    - git commit -m "pulled changes from Shisho Cloud"

    - |
      git push gitlab_origin \
        -o merge_request.create \
        -o merge_request.target=main \
        -o merge_request.title="${MR_TITLE}" \
        -o merge_request.description="${MR_DESCRIPTION}" \
        -o ci.skip
```

:::note
上記のジョブは差分を検知した場合にマージリクエストを作成しますが、代わりに例えば Slack に通知を送ることもできます。その場合は、`# Commit changes and push` のステップの代わりに以下のようなステップを追加すると良いでしょう。`SLACK_WEBHOOK_URL` の取得方法や使い方については、[公式サイト](https://api.slack.com/messaging/webhooks)をご参照ください。

```yaml
# Notify slack
- >
  curl -X POST \
    -H 'Content-type: application/json' \
    --data "{ \"text\": \"Shisho Cloud とリポジトリの間にワークフローの差分を検知しました\"}" \
    ${SLACK_WEBHOOK_URL};
```

:::

編集が完了したらコミットして GitLab にプッシュしてください。

最後にパイプラインスケジュールを設定します。GitLab のプロジェクトページから「ビルド」>「パイプラインスケジュール」を開いて「新しいスケジュール」もしくは「新しいパイプラインスケジュールを作成」をクリックしてください。

「新しいパイプラインのスケジュールを作成」を開くと以下の内容を入力してください:

|                                         |                                     |
| --------------------------------------- | ----------------------------------- |
| **説明:**                               | `Shisho Cloud workflows diff check` |
| **間隔のパターン:**                     | `カスタム`**:** `0 0 * * *`         |
| **Cron のタイムゾーン:**                | ` [UTC+9] Tokyo`                    |
| **ターゲットブランチまたはタグを選択:** | `main`                              |
| **変数:**                               | なし                                |
| **有効化:**                             | :white_check_mark:                  |

![GitLab の CI/CD の変数の画面](/docs/ja/_md-assets/607515889a-create-pipeline-schedule.png)

「パイプラインスケジュールを作成」をクリックるすと、スケジュールの設定が完了です。

これにより、リポジトリ内と Shisho Cloud 上のワークフローが一致しているかどうか定期的にチェックされるようになりました。ここから先は、実際に Web インターフェースから直接ワークフローを編集し、GitLab CI/CD がワークフローの差分を正しく検出できることを確認していきましょう。

まず[デモのワークフロー `demo-notification` の編集画面](https://cloud.shisho.dev/*/workflows/edit?wfid=demo-notification)を開きます。

このワークフローのマニフェストを例えば以下のように編集し、「保存」ボタンをクリックしましょう。

```yaml
version: 0.1.0
id: "demo-notification"
# highlight-next-line
name: "DEMO: Send notifications to various channels (edited from console)"
triggers: {}
jobs:
- id: group
  name: Send to notification groups
  notify:
    rego: |
      package demo.notification.group

      import data.shisho

      notifications[n] {
        input.running_state == shisho.job.running_state_preprocessing

        data.params.group != ""
        n := shisho.notification.to_group(
          data.params.group,
# highlight-next-line
          "hello! (edited from console)",
        )
      }
# 後略
```

次に、GitLab のプロジェクトページから「ビルド」>「パイプラインスケジュール」を開いて今回作成したスケジュールの実行ボタンをクリックしてください。

![GitLab のパイプラインスケジュール画面](/docs/ja/_md-assets/b56e6a0ce9-pipeline-schedules.png)

このチュートリアルで作成した GitLab CI/CD のジョブによって、Web インターフェースから加えた変更を取り込むマージリクエストが作成されているはずです。先ほどの変更が確かに反映されていることを確認してみましょう。

![GitLab の自動作成されたマージリクエスト](/docs/ja/_md-assets/739169bcef-merge-request.png)

このように、Shisho Cloud の Web インターフェースでワークフローが変更されたとしても、先ほど作成した GitLab CI/CD のジョブにより、その変更を検知してリポジトリに取り込むことができます。ここでは既存のワークフローを変更した際の実行結果を確認しましたが、Web インターフェースからワークフローを新規作成したり削除したりした場合にも、このジョブによってその変化を GitLab のリポジトリに取り込むことができます。
