好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

licensedでOSSのライセンスチェック

以前も下記の記事で話題にした、開発したソフトウェアで使用しているOSSのライセンス確認、面倒だけどやらなきゃですよねという話。

kusuwada.hatenablog.com

この記事ではOSSのリストアップやライセンスチェックを助けてくれるツール・サービスの紹介をしましたが、今回はここでも紹介した github 製の licensed を使ってみたので、使い方と使ってみた結果を紹介します。

github.com

機能

  • 必要なライブラリをinstallした状態で、使用しているOSSを依存関係も含めて全てチェックしてくれる
  • list: 依存関係を含めたライブラリ情報を出力
  • cache: ライセンスとメタ情報をファイルに出力
  • status: 設定に従い、許可されていないライセンスやライセンスが不明のライブラリがないかをチェックします
  • Rubyのツール、外部への通信は行わない
  • ※完全なOSSライセンスソリューションではないので、免責事項を理解して使用してください(本体READMEより)

自分が使ってると認識しており、パッケージ管理ファイルにちゃんと書いているようなライブラリのみであれば、開発規模によっては人手でOSSのリストアップとライセンス形式の調査は不可能ではないです。
が、依存関係を持つライブラリについては、依存先のライブラリも認識してなくても使用しているわけで、その辺までケアしようとすると人力でやるのは非現実的になってきます。と言うか無理。
ということで、licensedのようにライブラリの依存関係まで洗い出してくれるのは素晴らしい!

対応言語 (ライブラリ管理方式)

最新情報は こちらを参照。
2018年11月現在は、下記の言語・ライブラリ管理方式に対応。

  • Bower (bower)
  • Bundler (rubygem)
  • Cabal (cabal)
  • Go (go)
  • Go Dep (dep)
  • Manifest lists (manifests) # 自分で定義するので、基本どの言語でもかける
  • NPM (npm)
  • Pip (pip)
  • Git Submodules (git_submodule)

今回はニーズが高そうな rubygem, npm, pip について試してみました。

セットアップ

必要な環境

  • ruby
  • bundler
  • cmake
    • 公式READMEにもありますが、cmakepkg-config が必要です。
    • macOS with homebrew: brew install cmake pkg-config
    • ubuntu: apt-get install cmake pkg-config
    • centos: yum install cmake pkg-config

チェック対象の準備

rubygem

チェックしたい Gemfile のおいてあるディレクトリで下記を実施。

$ bundle install --path vendor/bundle

npm

チェックしたい package.json のおいてあるディレクトリで下記を実施。

$ npm install

pip

pip(python)の場合は少し複雑です。virtualenv環境が必要になります。
下記のコマンドでvirtualenvをインストール、virtualenv環境を設定/activateします。
VIRTUALENV_DIR はvirtualenv環境を動作させるディレクト

$ pip install virtualenv
$ virtualenv {VIRTUALENV_DIR} --no-site-packages
$ cd {VIRTUALENV_DIR}
$ source bin/activate

チェック対象リポジトリのcloneと ライブラリのinstallを実施します。
TARGET_REPO はチェック対象リポジトリ

$ git clone {TARGET_REPO}

チェックしたい requirements.txt 全てに対して下記を実施。

$ pip install -r requirements.txt

全部のライブラリをインストールできたら、下記を実施。
SOURCE_DIR は 後で .licensed.yml などの設定ファイルに書く。

$ pip freeze -l > {SOURCE_DIR}/requirements.txt

仮想環境はここで抜けて構わないのでこのあたりで

$ deactivate

licensed インストール

今回の構成はこんな感じにします。

(pythonの場合はVIRTUALENV_DIR)
└── my-app
    ├── .licensed
    │   └── .licensed.yml
    ├── app/
    │   ├── Gemfile
    │   ├── package.json
    │   └── requirements.txt
    ├── test/
    └── infra/

本番コードは app ディレクトリ配下に入っているとします。

$ cd {my-app}/.licensed
$ bundle init
$ echo "gem 'licensed', :group => 'development'" >> Gemfile
$ bundle install --path vendor/bundle

※licensedの変更に合わせて必要な環境が変わる可能性があります。 公式ページのInstallationはこちら

設定ファイルを用意します。
形式は yaml でも json でも対応しているそうですが、今回は yaml にします。
詳細は公式ページに載っているので、今回は最低限の設定にします。
設定ファイルについての詳細(公式README)はこちらを参照

source_path: '.licensed'  # ※1
cache_path: './.licensed/.licenses' # ※2

python:  # pythonの際はこの設定が必要
  virtual_env_dir: '{virtualenv_directotyの絶対パス or my-appからの相対パス}'   

# 一部のsourceだけ有効にしたい場合に使用します
# default(記述なし)では、発見されたすべてのsourceに対してパースします
sources:
  rubygem: false
  pip: true

# 以下、status 機能で使用。
# 使用を許可するライセンスの一覧。
allowed:
  - mit
  - apache-2.0
  - bsd
  - etc...

# レビュー済みlibraryの記載
# licensedでは検出ミスもあるため、問題ないと確認できたlibraryはここに記載します。
reviewed:
  rubygem:
    - bcrypt-ruby
  pip:
    - Flask     # bsd
    
# 無視リスト
# licensedがライセンス表記を発見できなかったが、問題がないと確認できたlibrary。
ignored:
  rubygem:
    - bundler
  pip:
    - pycrypto  # public domain
    - Cerberus

※1 source_pathについて

※2 cache_pathについて

  • cache機能を利用する時、ライブラリの情報を出力するパス。絶対パス or my-app からの相対パス

実行と出力イメージ

cache機能

見つかったライブラリを依存関係も含めてリストアップします。

$ cd {my-app/.licensed}
$ bundle exec licensed cache

{my-app}/.licensed/.licenses/ 配下に、発見されたsourceごとのdirectoryが作成されます。

{my-appy}/.licensed/.licenses
.
└── pip
    ├── PyYAML.txt
    ├── certifi.txt
    ├── chardet.txt
    ├── idna.txt
    ├── requests.txt
    └── urllib3.txt
└── npm
    ├── ...

それぞれのテキストにはライセンス情報が書かれています。PyYAML.txtの例。

---
type: pip
name: PyYAML
summary: YAML parser and emitter for Python
homepage: http://pyyaml.org/wiki/PyYAML
version: '3.13'
license: mit
---
Copyright (c) 2017-2018 Ingy döt Net
Copyright (c) 2006-2016 Kirill Simonov

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

これらのテキストをパースしてライセンス情報一覧を作ると、そのままどこかに提出も出来ますね。

status機能

見つかったライセンスに許可していないものが入っていないかチェックします。

$ cd {my-app/.licensed}
$ bundle exec licensed status

こんな感じで結果が出力されます。

Checking licenses for My App: 6 dependencies
FFF.FF

Warnings:

/Users/Natsumi/workspace/venv/test-licensed/.licensed/pip/certifi.txt:
  - license needs reviewed: other.

/Users/Natsumi/workspace/venv/test-licensed/.licensed/pip/chardet.txt:
  - missing license text
  - license needs reviewed: none.

/Users/Natsumi/workspace/venv/test-licensed/.licensed/pip/idna.txt:
  - license needs reviewed: other.

/Users/Natsumi/workspace/venv/test-licensed/.licensed/pip/requests.txt:
  - license needs reviewed: other.

/Users/Natsumi/workspace/venv/test-licensed/.licensed/pip/urllib3.txt:
  - license needs reviewed: other.

6 dependencies checked, 5 warnings found.

ここで warning が出たライブラリを確認し、ライセンスに問題がなければ .licensed.yml

  • reviewed
  • ignored

に追記します。本ライブラリの注釈にもあったようにlicesnedは完璧なソリューションではないですし、何ならpythonでよく使われている BSD ライセンスは検出できないなど性能はまだまだ改善の余地ありです。
今回は6つのライブラリ中1つしか認識できませんでした。(認識失敗のものは bsd や mit でした。)
reviewed, ignored リストを上手に使いつつ運用していくのが良いかと思います。

リストに入れて再度実行すると、このようなログになります。

$ bundle exec licensed status
Checking licenses for my-app: 6 dependencies
......
6 dependencies checked, 0 warnings found.

当面はこんな感じで除外リストが膨大になりそうですが、それでもぽっと入ってしまった許可していないライセンスのライブラリを、傷が浅いうちに検知できるのは魅力的だと思います。
検出の性能については、せっかくOSSとして公開されているので、皆でブラッシュアップしていきましょう!割とプルリクは受け入れてもらいやすそうに感じました。

まとめ

  • Pythonでのセットアップは少々面倒
  • 割と使われる BSD ライセンスが検出できないなど、性能はまだ改善の余地あり
  • OSSライブラリなので、是非一緒に育てていきましょう!

2018/12/22(土)更新:
他のツールも試してみたろころ格段に性能が上がったので、こっちのほうがお勧め!的な記事を書きました。やりたいことは全く同じなのでよろしければこちらもご覧ください。

kusuwada.hatenablog.com

参考リンク

OSSライブラリのライセンスをチェックしてくれるGitHub製ツール「licensed」 - Engineer's Way