# Local Scannerを使用したJenkinsのPRゲーティング

Aikido Local Scannerを使用すると、CIパイプラインでセキュリティゲートを適用できます。

{% hint style="info" %}
クラウド接続されたワークスペース（GitHub、BitBucketなど）でもPRゲーティングを使用できます。CIの[インテグレーションセクション](https://help.aikido.dev/section/ci-integrations/sg3q6UrIf4qE)をご覧ください。
{% endhint %}

PRゲーティングは、新しいコードがデフォルトブランチにマージされる前に、セキュリティ基準を満たしていることを保証します。スキャン対象はプルリクエストで導入された変更のみです。設定した重大度のしきい値以上の新しい問題が検出された場合、CIパイプラインは失敗します。

これにより、既存の検出結果は別途対処しつつ、新しい脆弱性の混入を防ぐことができます。

{% hint style="info" %}
リリース時にチェックを適用したいチーム向けに、[リリースゲーティング](https://help.aikido.dev/docs/docs-ja/container-image-scanning/local-image-scanning/release-gating-for-container-images-using-local-image-scanner)もサポートしています。
{% endhint %}

PRゲーティングを有効にするには、`--fail-on <severity>` オプションを追加して希望する重大度レベルを選択します。次に、`--gating-mode pr` オプションを追加して、PRゲーティングを実行することを指定します。また、ベースコミット（`--base-commit-id <commit-id>`）とヘッドコミット（`--head-commit-id <commit-id>`）も指定する必要があります。ベースコミットIDに対して以前にスキャンが実行されている場合は、スキャン結果がその結果と比較されます。そうでない場合は、デフォルトブランチでの最新のスキャン結果と比較されます。

Jenkins環境でのLocal Scannerのセットアップに関する一般的な情報については、[こちらの記事](https://help.aikido.dev/docs/docs-ja/code-scanning/local-code-scanning/github-action-setup-for-local-code-scanning)をご覧ください。

#### 仕組み

構成要素は3つあります。

1. &#x20;**SCMとJenkinsの間のインテグレーション。**
2. _Discover pull requests_ の動作を設定した **Multibranch Pipelineジョブ**。これにより、Jenkinsは開いている各プルリクエストをビルドします。PRビルドでは、Jenkinsはソースブランチをチェックアウトし、標準の変更リクエスト用環境変数（`CHANGE_ID`、`CHANGE_TARGET`、`CHANGE_BRANCH`）を公開します。
3. `Jenkinsfile` から `--gating-mode pr` で実行される **Aikido Local Scanner**。

```
PR opened/updated  ──►  SCM sends webhook  ──►  Jenkins Multibranch PR build
                                                      │
                                                      ▼
                                        aikido-local-scanner --gating-mode pr
                                                      │
                                  new issues ≥ --fail-on?  ── yes ──► build FAILS
                                                      │                    │
                                                      no                   ▼
                                                      ▼            build status = FAILED
                                                build PASSES               │
                                                      │                    ▼
                                                      ▼          SCM blocks merge
                                              SCM checks pass
```

#### Multibranch Pipelineのセットアップ

プルリクエストのビルドには **Multibranch Pipeline** ジョブが必要です。

1. Jenkinsで **New Item → Multibranch Pipeline** を選択し、名前を付けて **OK** を選択します。
2. **Branch Sources** で、**Add source → 使用しているSCMを選択** します。
3. **リポジトリ** を選択します。
4. **Behaviors** で **Add → Discover pull requests** を選択し、**Discover branches** を無効にします。
5. **Scan Multibranch Pipeline Triggers** で、**webhook trigger → Pull request opened or source branch updated** オプションを有効にします。
6. **Build Configuration** は **by Jenkinsfile** のままにし、**Script Path** = `Jenkinsfile` とします。
7. **Save** を選択します。Jenkinsがリポジトリをスキャンし、開いている各プルリクエストのビルドを開始します。

#### JenkinsfileにAikido PRゲーティングステージを追加する

リポジトリのルートに `Jenkinsfile` を追加（または既存のものを拡張）します。以下のステージは **プルリクエストのビルドでのみ** 実行され、Gitからベースコミットとヘッドコミットを取得し、PRゲーティングモードでスキャナーを実行します。ゲートが失敗した場合にスキャナーがゼロ以外の終了コードを返すことで、ビルドが失敗します。

```groovy
pipeline {
    agent any

    environment {
        // Picks up credentials as setup in https://help.aikido.dev/code-scanning/local-code-scanning/jenkins-setup-for-local-code-scanning#id-1-get-your-authentication-token
        AIKIDO_API_KEY = credentials('aikido-local-scanner-api-key')
        AIKIDO_REPO_NAME = 'my-repo'
    }

    stages {
        stage('Aikido PR Gating') {
            // CHANGE_ID is only set on pull request builds
            when { expression { env.CHANGE_ID != null } }
            steps {
                script {
                    // Ensure the target (destination) branch is available locally
                    sh "git fetch origin ${env.CHANGE_TARGET}"

                    // Head = tip of the PR source branch (what's being merged in)
                    def headCommit = sh(
                        script: 'git rev-parse HEAD',
                        returnStdout: true
                    ).trim()

                    // Base = tip of the destination branch (what it's merging into)
                    def baseCommit = sh(
                        script: "git rev-parse origin/${env.CHANGE_TARGET}",
                        returnStdout: true
                    ).trim()

                    echo "PR #${env.CHANGE_ID}: ${env.CHANGE_BRANCH} -> ${env.CHANGE_TARGET}"
                    echo "Base commit: ${baseCommit}"
                    echo "Head commit: ${headCommit}"

                    // Docker variant. The scanner exits non-zero when new issues
                    // at or above --fail-on are found, which fails the build.
                    sh """
                        docker run --rm \
                          -v "\$(pwd):/scan-target" \
                          aikidosecurity/local-scanner \
                          scan /scan-target \
                          --apikey "\$AIKIDO_API_KEY" \
                          --repositoryname "\$AIKIDO_REPO_NAME" \
                          --branchname "${env.CHANGE_BRANCH}" \
                          --gating-mode pr \
                          --fail-on critical \
                          --base-commit-id ${baseCommit} \
                          --head-commit-id ${headCommit}
                    """
                }
            }
        }
    }
}
```

Dockerではなく **エージェントにスキャナーのバイナリがインストールされている場合** は、`docker run …` ブロックを以下に置き換えます。

```groovy
sh """
    aikido-local-scanner scan ./ \
      --apikey "\$AIKIDO_API_KEY" \
      --repositoryname "\$AIKIDO_REPO_NAME" \
      --branchname "${env.CHANGE_BRANCH}" \
      --gating-mode pr \
      --fail-on critical \
      --base-commit-id ${baseCommit} \
      --head-commit-id ${headCommit}
"""
```

* **`--fail-on critical`** は重大度のしきい値を設定します。より厳しくゲーティングするには、`high`、`medium`、または `low` に変更してください。

必要に応じて、SCMでゲートの適用を設定してください。
