開発者のためのSPDX入門-ライセンス管理の理想と現実
PredNextの永井です。昨年PredNextに入社しました。前職では通信規格の国際標準化やその社会実装にも携わり、「共通フォーマットで情報を交換する」ことが技術を社会に広げるうえでいかに重要かを実感してきました。ソフトウェアのライセンス管理もまた、共通フォーマットが求められる領域の一つです。
現代のソフトウェア開発では、依存パッケージが100を超えることも珍しくありません。これらすべてのライセンスを正確に把握・管理できていますか?本稿では、ライセンス管理の課題を整理したうえで、ソフトウェア開発者が今日から活用できる「SPDXライセンスリスト」について解説します。
あなたのプロジェクトで使っているパッケージ、すべて把握していますか?
AI開発を例に取ると、PyTorchは推移的依存関係も含めて約50のパッケージに依存しており、さらにそのPyTorchを利用するHugging Face Transformersは約100のパッケージに依存しています。こうした多数の依存関係すべてについて、エクセルなどを使って手作業で管理することは多大な労力と困難を伴うでしょう。
本稿では、この問題を解決するための標準規格であるSPDXについて解説します。まずはSPDXが生まれた背景であるSBOM(Software Bill of Materials)から説明します。
SBOM(Software Bill of Materials)
SBOM は「ソフトウェア部品表」と訳され、食品の原材料表示と同じ発想で、ソフトウェアに「何が含まれているか」を明確にするための仕組みです。
SBOMはセキュリティの観点から広まりました。米国では2020年末のSolarWindsサプライチェーン攻撃などを受け、2021年5月の大統領令 EO 14028により連邦政府調達ソフトウェアへのSBOM提供が義務化されました。同年12月に発見された「Apache Log4j」の深刻な脆弱性(Log4Shell)では多くの組織が影響範囲を即座に判断できず、SBOMの重要性が改めて認識されました。欧州でもサイバーレジリエンス法により2027年からSBOMの作成・維持が義務化されます。
SBOMの標準フォーマットにはSPDX、CycloneDX、SWIDなどがあります。本稿では、歴史が長くエコシステムでの採用が進んでいるSPDXに焦点を当てます。
SPDXとは
SPDX(Software Package Data Exchange) は、Linux Foundationが主導するSBOMのオープンスタンダードです。2010年から運営されており、ISO/IEC 5962:2021として国際標準化されています。SPDXプロジェクトは、以下の3つの要素で構成されています。
- Specification - SBOM仕様
- License List - ライセンス表記 <— 本稿のフォーカス
- Tools - 生成・検証ツール
SPDXの特徴は、ライセンス管理のための仕組みが充実していることです。
従来、ライセンス管理の自動化には多くの課題がありました。
第一に、表記ゆれの問題があります。 MIT、MIT License、Expat など同じライセンスでも表記がバラバラです。
第二に、ライセンスには複雑な事情があります。 コードの一部分だけ別ライセンスが適用される場合、利用者がどちらかを選択できるデュアルライセンスの場合など、単純な文字列では表現しきれないケースが存在します。Debianのcopyrightファイルは機械可読なライセンス宣言の先駆的な取り組みでしたが、GPLがv2もv3もすべて単なる「GPL」として丸められてしまうなど、依存ライブラリのライセンス管理には粒度が粗すぎました。
第三に、ライセンスを機械可読な形式で明示する標準的な方法がありませんでした。 リポジトリのトップに LICENSE や LICENSE.txt といった慣習的な名前のファイルがあるかどうかで判断するしかなく、ツールによる自動検出には限界があります。
SPDXはこれらの課題を解決するために、各ライセンスに一意の識別子を割り当てた「SPDXライセンスリスト」を提供しています。このリストはnpm、PyPI、Cargo、GitHubなど主要なパッケージマネージャやプラットフォームで標準的に採用されています。
SPDXライセンスリスト
SPDXライセンスリストは、ライセンスに 一意の識別子(SPDXライセンス識別子)を割り当てたリストです。これにより、ライセンスの特定と参照が標準化され、管理が容易になります。
主要なSPDXライセンス識別子
| 識別子 | ライセンス名 |
|---|---|
MIT | MIT License |
Apache-2.0 | Apache License 2.0 |
GPL-3.0-only | GNU GPL v3.0 only |
GPL-3.0-or-later | GNU GPL v3.0 or later |
BSD-3-Clause | BSD 3-Clause License |
GNUライセンス(GPL、LGPL、AGPL)では、対象バージョンを明示的に指定します。GPL-3.0ではなく、GPL-3.0-only(v3.0のみ)またはGPL-3.0-or-later(v3.0以降のバージョンを選択可)を使います。
例外(Exceptions)
例外は、ライセンスへの追加条項です。SPDXではGCC-exception-3.1、LLVM-exception、Classpath-exception-2.0などの識別子が定義されています。
特に重要なのは、コンパイラに関連する例外です。GCCやClangなどのコンパイラでプログラムをビルドすると、出力されたバイナリはコンパイラが提供するライブラリ(libgccやlibc++など)をリンクします。通常であれば、ユーザーのプログラムにもこれらのライブラリのライセンスに基づく義務(GPLの伝播やApache 2.0の帰属表示など)が発生しますが、例外はそれを免責します。 たとえば、GCC-exception-3.1はGCCが提供するライブラリとリンクしてもGPLが伝播しないようにする例外です。同様に、LLVM-exceptionはClangが提供するライブラリとリンクしてもApache 2.0の帰属表示義務を免責します。また、Classpath-exception-2.0はOpenJDKで使用され、独立したモジュールとリンクしてもGPLが伝播しません。
ライセンス式構文
SPDXの特徴的な仕組みが、このライセンス式構文です。従来、「MITかApache-2.0のどちらかを選べる」「GPLだが例外条項がある」といった複雑なライセンス条件は、自然言語で説明するしかありませんでした。しかし、SPDXがOR、AND、WITHという3つの演算子を定義したことで、こうした複雑な条件も機械可読な形式である程度表現できるようになりました。これにより、ツールによるライセンスの自動検出・集計・検証が現実的なものとなり、多数の依存パッケージをもつプロジェクトでもライセンス管理が容易になります。
複数のライセンスを表現する場合、以下の演算子を使います。
OR 演算子:デュアルライセンス
- 利用者はどちらかを選択できます
- 例:
MIT OR Apache-2.0(MITかApache-2.0を選択できる。Rust言語はこのライセンス。)
AND 演算子:複数条件
- 利用者は両方のライセンス条件を満たす必要があります
- 例:
LGPL-2.1-only AND BSD-3-Clause(LGPL v2.1と修正BSDライセンスの両方が課される。ライブラリの一部のファイルが別のプロジェクトから取り込まれており、そのファイルだけ異なるライセンスが適用されている場合などに発生する。)
WITH 演算子:例外条項の追加
- ライセンスに例外条項が追加されます
- 例:
GPL-2.0-only WITH Classpath-exception-2.0(GPL v2だが、独立したモジュールとリンクしても伝播しない)
Pythonエコシステムにおけるライセンス管理
Pythonでは、PEP 639においてpyproject.tomlにライセンスを記述する方法が定義され、License-ExpressionとLicense-Fileという2つのフィールドが規定されました。
[project]
name = "my-package"
license = "MIT" # または "MIT OR Apache-2.0" などのSPDXライセンス式構文
license-files = ["LICENSE", "NOTICE"]
License-ExpressionにはSPDXのライセンス式構文を書くことと規定されているので、機械的なライセンス管理にたいへん役に立つ仕組みです。将来的にはLicense-Expressionですべてが解決する理想的な未来がきて欲しいものですが、2026年現在は、まだまだ理想とは遠く、多くの問題があります。
PEP 639でLicense-Expressionが規定されてから1年以上になりますが、このフィールドに対応していないパッケージがたくさんあります。依存パッケージ群のライセンスを確認しようとすると、様々な問題に遭遇します。
- まったくPEP 639に対応していないパッケージ
- PEP 639対応の修正Pull Requestが放置されているパッケージ
- PEP 639対応の修正がマージされているがリリースされていないパッケージ
- 最新版ではPEP 639に対応済みだが、古いバージョンに依存してしまっているため
License-Expressionが読み取れない場合
これらのように調べれば比較的すぐにわかる問題だけではなく、ソースコードを読んで状況を確認しないとわからない難しい問題にもいくつか遭遇しました。
たとえば、ninjaはPyPIのライセンスメタデータが「Apache Software License, BSD License」となっていますが、実際にはApache-2.0が正しく、BSDは誤りです。他のパッケージからコピペする際に混ざったようで、弊社の徳永が修正PRを出しています。
また、torchaudioはBSDライセンスで配布されていますが、環境にffmpegがインストールされていればffmpegが利用されます。ffmpegは多くの場合--enable-gplオプション付きでビルドされており、GPLが適用されます。環境によってtorchaudioを経由して適用されるライセンスが変わるため注意が必要です。
さらに、soundfileはBSDライセンスで配布されていますが、内部で使用しているlibsndfileはLGPLです。C言語ライブラリのため機械可読なライセンス情報がなく、リポジトリを確認しなければ気づけません。
これらの事例が示すように、ツールによる自動検出だけに頼ることはできません。メタデータが間違っていることもあれば、環境によってライセンスが変わることもあり、ネイティブ依存関係は別途確認が必要です。
SPDXを活用する
上述の課題はあるものの、SPDXライセンス識別子を使うことで、ライセンス管理は確実に改善されます。完璧ではなくても、標準化された形式で情報を記述・取得することは、人手による確認作業を大幅に軽減します。
依存パッケージのライセンスを確認する
まず、自分のプロジェクトが依存しているパッケージのライセンスを確認してみましょう。各言語のエコシステムにはライセンス確認ツールがあります。
Python:pip-licenses
pip install pip-licenses
pip-licenses --format=markdown
出力例:
| Name | Version | License |
|---|---|---|
| numpy | 2.4.1 | BSD-3-Clause |
| packaging | 26.0 | Apache-2.0 OR BSD-2-Clause |
| uvicorn | 0.40.0 | BSD-3-Clause |
pip-licenses (v5.5.0) では、パッケージにPEP 639のLicense-Expressionメタデータがあれば、それが優先的に使用されます。License-Expressionがないパッケージについては、従来のTrove ClassifiersやLicenseメタデータにフォールバックします。
Node.js:license-checker
npx license-checker --summary
Rust:cargo-license
cargo install cargo-license
cargo license
自分のコードにSPDXライセンス識別子を書く
OSSを書く人は、自分のコードにもSPDXライセンス識別子を書きましょう。これにより、あなたのコードを利用する他の開発者がライセンスを正確に把握できるようになります。
ソースファイル
ファイルのコメント(shebangや著作権表示の前後)に記述します。
# SPDX-License-Identifier: MIT
pyproject.toml(Python)
PEP 639に従い、SPDXライセンス式構文を記述します。
[project]
name = "my-package"
license = "MIT"
license-files = ["LICENSE"]
package.json(npm)
{
"name": "my-package",
"license": "MIT"
}
Cargo.toml(Rust)
[package]
name = "my-package"
license = "MIT OR Apache-2.0"
まとめ
本稿では、ライセンス管理の課題とSPDXによる解決策を紹介しました。
- 表記ゆれは、SPDXライセンス識別子により一意に特定できるようになりました。
- 複雑なライセンス条件は、ライセンス式構文(
OR、AND、WITH)で機械可読な形式で表現できるようになりました。 - 明示場所の不統一は、SPDXによるライセンス表記の標準化を受けて各パッケージマネージャ(npm、PyPI、Cargo)がSPDX形式を採用したことで、解決に向かっています。
また、Pythonエコシステムにおける標準化(PEP 639)の現状と、実際の現場で遭遇する課題についても紹介しました。
SPDXによるライセンス管理は完璧ではありません。メタデータの誤り、環境による差異、ネイティブ依存関係の問題など、ツールだけでは解決できない課題があります。しかし、主要なパッケージマネージャでSPDXライセンス識別子の採用が進み、2027年にはサイバーレジリエンス法によるSBOM義務化も始まります。標準化の波はライセンス管理の精度を高め、エコシステム全体の透明性を向上させていくでしょう。
お仕事募集中です
今回はSPDXについてご紹介しましたが、弊社の本業はAI関連のコンサルティング等のサービス提供です。 実践的なAI活用にご興味のある方はお問い合わせフォームからご連絡ください。お待ちしております。