4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Self-hostedなGitlabでもdependabotを使いたい

Last updated at Posted at 2023-10-24

はじめに

Dependabot(正確にはDependabot security updates)はリポジトリで使用している外部のライブラリやパッケージのアップデートを検出して、外部パッケージの管理ファイル(*1)に対する修正リクエスト(*2)を自動で作成してくれるツールです。

DependabotはGithubに買収されています ので、開発元はGithubとなります。
そのため、GithubではDependabotがサッと使えるようになっているのですが、同じことをself-managedなGitlabでもやってみたいと思います。

Dependabotのことをより知りたい人は Github Docs - Code security - Dependabot を使用してサプライ チェーンを安全に保つ を読んでみましょう。

(*1) Pythonで言うrequirements.txtや、Goで言うgo.modなどです
(*2) 言わずもがな、Gitlabではマージリクエストのことです

環境の前提

Gitlabの環境についてはお手元のものをお使いください。
一から構築する場合は GitlabとKanikoによるコンテナの自動ビルド&配布環境の構築 でも紹介しています。
UIや操作面で若干違いがあるかもしれませんが、参考にしていただければ幸いです。

以降は以下の設定が終わっている前提で進行します。

  • GitlabおよびGitlab runner(Docker)が設定済み
  • 空っぽのプロジェクトが作成済み
    • 今回は qiita/dependabot を作りました
  • ユーザーはGitlabに対してgit pull/pushするためのgit設定が完了している
  • Githubのアカウントを持っている(dependabotで使用するトークン取得のため)

サンプルプロジェクトの作成

まずは、Dependabotでパッケージ更新をチェックするためのサンプルコードを作成します。
空のプロジェクトを取得してスタートです。

git clone http://qiita-gitlab.example.com/qiita/dependabot.git
cd dependabot

今回はPythonでやってみましょう。
Dependabotに関する設定などは後で行うので、ここでは以下の2ファイルだけを作成します。
http://localhost:8080 にGETリクエストを送るだけの簡単なプログラムです。

2023/10/13 時点ではrequestsの最新版は2.31.0です。この後の手順では、dependabotの設定をすることで、requestsパッケージのアップデートをするマージリクエストが作成されることを確認していきます。

requirements.txt

requests==2.29.0

sample.py

import requests


def get(url):
    resp = requests.get(url)
    print(f"GET {url} returned {resp.status_code}")


if __name__ == '__main__':
    get("http://localhost:8000")

もちろん通信相手がいなければ例外がドバーっと出力されるわけですが、本題では無いので気にしないでください。

あとは、これらのコードをリポジトリに格納します。

git switch --create main
git add requirements.txt 
git add sample.py 
git commit -m "Add sample code"
git push --set-upstream origin main

Dependabotの導入にあたって

DependabotはGithubが開発していますが dependabot-coreはOSSとして公開 してくれています。
これを使って Gitlabでdependabotを動かすプロジェクト がありますので、これを参考に導入していきます。

特に参考になるのは同プロジェクトの standalone の部分の説明ですね。

Application can be used in a stateless cli like mode. This mode is most useful to run dependency updates from Gitlab CI. dependabot-gitlab/dependabot-standalone describes the best way to run dependency updates from gitlab ci. Like docker compose, all configuration is done via environment variables.

というわけで https://gitlab.com/dependabot-gitlab/dependabot-standalone をに見に行くと、サンプルとなる .gitlab-ci.yml と README.md が置かれています。

必要なトークンは以下の2つです。

  • SETTINGS__GITLAB_ACCESS_TOKEN - gitlab personal access token with api access scope and at least Developer role
  • SETTINGS__GITHUB_ACCESS_TOKEN - github personal access token with repository read scope

更に、スケジューラ登録時に必要な変数は以下の3つです。

  • PROJECT_PATH - project path, like dependabot-gitlab/dependabot
  • PACKAGE_MANAGER_SET - comma separated package eco-systems, like bundler,docker (dependency file must be in the same directory for multiple package managers to work within same schedule job)
  • DIRECTORY - update directory, usually / if not a larger monorepo

そこで、サンプルプロジェクトに手を入れる前に、まずは必要なトークンを取得します。

Githubトークンの取得

GithubアカウントのSettings左下の "Developer settings" を選択します。

image.png

Personao access tokensからclassicのトークンを選択します。

image.png

アクセスが必要なのは public_repo だけです。Expirationは各自の用途に合わせて設定してください。

image.png

トークンが生成出来たらすぐ後で使うので保存しておきます。

Gitlabトークンの取得

Gitlabに対しては、Dependabotがプロジェクトにマージリクエストを作成するための権限が必要です。
今回はプロジェクトアクセストークンを発行して、プロジェクト固有で使えるようにします。

image.png

必要な権限は api スコープに対して Developer ロールが必要です。

image.png

Gitlabではトークンの有効期限は最長1年となっていますが、指定しないとデフォルトで1年になります。

GitlabプロジェクトのCI/CD変数設定

取得したトークンをプロジェクトのCI/CD変数に設定しておきます。

image.png

変数名は SETTINGS__GITLAB_ACCESS_TOKENSETTINGS__GITHUB_ACCESS_TOKEN が予約名なので、その通りにします。

image.png

  • Protect variable については、以降の手順で動作確認用のブランチを作成するため、一時的にOFFにしておきます
  • Mask variable はトークンがログに出力されないようにONにしておきましょう
  • Expand variable reference はデフォルトのONで良いです

Dependabotのコード追加

Pythonだけなので https://gitlab.com/dependabot-gitlab/dependabot-standalone/-/blob/main/.gitlab-ci.yml の中からPythonに関係する部分だけを抜き出して、以下のような .gitlab-ci.yml を作成します。

今回は例示のために必要部分だけを抜き出していますが、通常は上記のリポジトリからファイルをそのまま取得して、includeするのが簡単で良いでしょう。

この記事では 3.5.0-alpha.1 を使用していますが、最新のリリース状況については https://gitlab.com/dependabot-gitlab/dependabot/-/releases を参照してください。

default:
  image: python:3.11.6-slim
  tags:
    - docker

variables:
  DEPENDABOT_GITLAB_IMAGE: docker.io/andrcuns/dependabot-gitlab
  DEPENDABOT_GITLAB_VERSION: 3.5.0-alpha.1

.dependabot-gitlab:
  image:
    name: ${DEPENDABOT_GITLAB_IMAGE}-${CI_JOB_NAME}:${DEPENDABOT_GITLAB_VERSION}
    entrypoint: [""]
  variables:
    GIT_STRATEGY: none
    RAILS_ENV: production
    SECRET_KEY_BASE: key
    PACKAGE_MANAGER: $CI_JOB_NAME
    SETTINGS__GITLAB_URL: $CI_SERVER_URL
    SETTINGS__STANDALONE: "true"
    SETTINGS__LOG_COLOR: "true"
  script:
    - cd /home/dependabot/app
    - bundle exec rake "dependabot:update[${PROJECT_PATH?},${PACKAGE_MANAGER?},${DIRECTORY?}]"

pip:
  extends: .dependabot-gitlab
  rules:
    - if: $DEPENDENCY_UPDATES_DISABLED
      when: never
    - if: '$CI_PIPELINE_SOURCE == "schedule" && $PACKAGE_MANAGER_SET =~ /\bpip\b/'

更に、dependabotには https://gitlab.com/dependabot-gitlab/dependabot-standalone のREADMEに書かれているように .gitlab/dependabot.yml を作成する必要があります。

dependabot.ymlの形式はGithub公式の dependabot.yml ファイルの構成オプション に従って書くことになります。
上記の文書には package-ecosystem / directory / schedule.interval が必須となっていますが、スケジューラはGitlab側で設定することになるため schedule.interval は参照されません。
従って、Gitlabにおける最小限構成は以下のようになります。

version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"

それでは、新しくブランチを作成して、今作ったファイルを追加したらpushします。

git switch --create dependabot
git add .gitlab-ci.yml
git add .gitlab/dependabot.yml
git commit -m "Add dependabot"
git push --set-upstream origin dependabot

Dependabotの試験動作

それでは、Gitlabプロジェクトでスケジューラを設定してDependabotを動かしてみましょう。

image.png

設定値は以下の通り。

  • Description: なんでも良いです。とりあえずdependabotと書きました。
  • Interval Pattern: 状況に合わせて設定してください。今回はデフォルトのEvery day。
  • Cron timezone: 状況に合わせて設定してください。とりあえず日本にいるのでTokyo。
  • Select target branch or tag: 試験動作なので、先ほどpushした dependabot ブランチを選択。
  • Variables
    • PROJECT_PATH : 今回は qiita/dependabot になります
    • PACKAGE_MANAGER_SET : 今回は pip になります
    • DIRECTORY : 今回は / になります
      • モノレポなどで、プロジェクトファイルが下の階層にある場合は、構成ファイルが置かれているディレクトリを指定します。
    • SETTINGS__CONFIG_BRANCH : 今だけ dependabot を設定します。これは .gitlab/dependabot.yml を取得するブランチを指しており、mainブランチにマージするまでは設定しておきます。
  • Activated: 試験動作が終わるまではOFFにしておきます。

image.png

それでは、作成したスケジューラを実行してみましょう。

image.png

Pipelineが成功したら、Merge requestsが1件増えたようです。

image.png

古いパッケージが検出されて、マージリクエストが作成されました!

image.png

マージリクエストにはRelease NoteやVulnerabilities fixedが書かれており、いちいち調べに行かなくてもサマリーがまとまっています。
このVulnerabilities fixedについては、情報源がGitHub Advisory Databaseなので CVE-2023-32681 のページに書かれている内容と同じ文章が使われているはずです。

image.png

Dependabotが作成するマージリクエストの文章粒度はパッケージの作成者によるため、必ずこれだけの情報量があるわけではありません。
とはいえ、大抵リポジトリにタグが打ってあるので、コミット一覧くらいは最低限取得できると思ってよいでしょう。

そして、requestsパッケージを2.31.0にアップデートする変更がちゃんと加えられています。

image.png

変更に問題がなければ、このマージリクエストはそのままマージしてしまいましょう。

CIコードのマージと後始末

最後に、動作確認が出来てmainブランチ(Protectedなブランチ)にマージしたら、試験動作用の設定を削除して、定期実行を有効にします。

  • CI/CD -> Schedules -> dependabot
    • Select target branch or tag を main に変更(※各自のブランチ戦略に合わせてください)
    • Variables SETTINGS__CONFIG_BRANCH を削除
    • Activatedにチェックを入れて、定期実行を有効化
  • Settings -> CI/CD -> Variables
    • SETTINGS__GITHUB_ACCESS_TOKEN のFlagsで Protect variable を有効化
    • SETTINGS__GITLAB_ACCESS_TOKEN のFlagsで Protect variable を有効化
    • これで、Protectedなmainブランチ以外ではdependabot用のトークンが参照できなくなります。

設定変更後に再度手動でdependabotのパイプラインを実行し、念のため完走することを確認して完了です。
パッケージの更新が無ければ重複したマージリクエストは作られませんので、何度実行しても大丈夫です。

おしまい

最初は勢いでソフトウェアを作ってみたものの、ふと目を離すと知らない間に依存ライブラリがアップデートされている...というのは良くある話ですよね。
自分の書いたコードには更新が無いけど、依存ライブラリの更新が無いか定期的にチェックできると、とても便利です。
脆弱性が見つかったパッケージにすぐ対応できるので、セキュリティリスクを減らすことが出来るでしょう。

それだけでなく、Dependabotの作るプルリクエスト(マージリクエスト)には、Release NoteやChangelogが書かれているのがとても親切です。
あると便利なのになと思っていた機能がある日追加されているのに気付いたり、知らない機能に対応したRelease Noteを見て新しい知識を取り入れたり、自身のアップデートにも活用できます。

是非色々なプロジェクトに導入してみてください。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?