EmotionTechテックブログ

株式会社エモーションテックのProduct Teamのメンバーが、日々の取り組みや技術的なことを発信していくブログです。

cargo-deny によるクレートのライセンス確認

はじめに

こんにちは。バックエンドエンジニアのよしかわです。Rust を用いた大抵のソフトウェア開発では何らかの外部クレートを用いるかと思います。crates.io で公開されているようなクレートは MIT や Apache-2.0 といったライセンスを採用していることが多いですが、それ以外のライセンスを採用していることもあります。間違えてプロダクトに合わないライセンスのクレートを利用しないようにするにはプログラムによる機械的な確認が有効です。そこで今回はクレートのライセンスを cargo-deny によって確認する方法をご紹介します。

インストール

他の cargo プラグインと同じく cargo install でインストールできます。

cargo install --locked cargo-deny

cargo binstall でもインストールできます。

cargo binstall cargo-deny

設定

設定は deny.toml というファイルで行います。deny.toml は下記を実行すると生成されます。

cargo deny init

以下に抜粋したのは cargo-deny 0.18.0 により生成された deny.toml のうちライセンスの確認に関する部分です。丁寧なコメントがついておりドキュメントも充実しているのであまり設定で困ることはないと思いますが、参考までにいくつか補足してみようと思います。

# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
    #"MIT",
    #"Apache-2.0",
    #"Apache-2.0 WITH LLVM-exception",
]
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
    # Each entry is the crate and version constraint, and its specific allow
    # list
    #{ allow = ["Zlib"], crate = "adler32" },
]

# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
#[[licenses.clarify]]
# The package spec the clarification applies to
#crate = "ring"
# The SPDX expression for the license requirements of the crate
#expression = "MIT AND ISC AND OpenSSL"
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
# Each entry is a crate relative path, and the (opaque) hash of its contents
#{ path = "LICENSE", hash = 0xbd0eed23 }
#]

[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
    #"https://sekretz.com/registry
]

allow (許可リスト)

まず必要な設定が冒頭の allow = [ ... ] の部分です。生成された設定では何も許可されていないので、この状態で cargo deny check licenses を実行してエラーになったものから一つずつ確認して追加するのが簡単だと思います。このとき出力されるエラーメッセージもかなり分かりやすいです。

error[rejected]: failed to satisfy license requirements
  ┌─ registry+https://github.com/rust-lang/crates.io-index#regex@1.11.1:4:12
  │
4 │ license = "MIT OR Apache-2.0"
  │            ━━━────━━━━━━━━━━
  │            │      │
  │            │      rejected: license is not explicitly allowed
  │            license expression retrieved via Cargo.toml `license`
  │            rejected: license is not explicitly allowed
  │
  ├ MIT - MIT License:
  ├   - OSI approved
  ├   - FSF Free/Libre
  ├ Apache-2.0 - Apache License 2.0:
  ├   - OSI approved
  ├   - FSF Free/Libre

具体的なライセンスの内容については原文に当たる以外に下記の日本語情報も参考になるかと思います。

[[licenses.clarify]] (ライセンス情報の明示的な設定)

cargo-deny がライセンス情報を読み取れないようなクレートがある場合、 [[licenses.clarify]] の設定で cargo-deny にライセンス情報を伝えられます。具体例として、生成された deny.toml には ring の場合の設定がコメントに記載されています。なお最近リリースされた ring 0.17.10 以降のバージョンではライセンス情報の記載方法が変わりこの設定は不要となったようです。

[licenses.private] (非公開クレート向けの設定)

企業内で開発しているような非公開のクレートを cargo-deny によるライセンス確認の対象外とする場合、非公開クレートの Cargo.toml に publish = false を設定した上で、deny.toml の [licenses.private]ignore = true を設定します。そうすると cargo-deny は非公開クレートのライセンス情報を無視します。

特定リポジトリのクレートのライセンスを無視したい場合は [licenses.private]ignore-sources にそのリポジトリを記載します。そうすると cargo-deny はそのリポジトリ内のクレートのライセンス情報を無視します。

[licenses.private]
ignore = true
ignore-sources = ["https://github.com/private-org/private-repo"]

実行

設定の項でも触れた通り、実行は cargo deny check licenses で行えます。もし GitHub Actions 上で実行するのであれば cargo-deny-action も使えます。README に設定例も記載されていて本当に至れり尽くせりです。

おわりに

今回はライセンスの確認方法についてご紹介しましたが、バージョンの混在(参考: Version-Incompatibility Hazards の検出)や脆弱性などの確認も cargo-deny で行えます。もし使ったことがないようでしたら一度試してみてはいかがでしょうか。

エモーションテックでは顧客体験・従業員体験の改善をサポートし世の中の体験を変えるプロダクトを開発しており、開発には Rust も利用しております。もし興味を持っていただけましたら、ぜひ採用ページからご応募をお願いいたします。

hrmos.co