動機
- ソースコード調査ツールの中には、調査対象となるソースコードのサイズで価格が決まるものがあります*1*2。そういったツールの利用価格を低く抑えるには、調査対象のソースツリーから不要なファイルはできるだけ除外したいところです。
- 米国大統領令でSBOMの開示がガイドラインに入った*3ので、開発したソフトウェアに不要な依存関係が入っているのは避けたいです。
概要
たとえばPythonであれば、requirements.txt
に記載されているパッケージだけをvirtualenv
にインストールすれば、不要なパッケージが調査対象に含まれることは避けられます。ですが、これで分かるのはpip
レベルの依存関係であって、たとえば実行環境には不要なテストケースがパッケージに含まれているとか、機能としては持っているけれど実際には使われていないファイルがあるとかの場合は除外できません。
プログラム実行時の依存関係ベースで不要なファイルを除外するには、C0 100%になるようなテストケースを実行したうえで、カバレッジが0%でないソースコードのみを残すというのがよさそうです。ただ、C0 100%になるテストケースが用意できない場合もあるでしょう。
本稿ではimport文の依存関係ベースで不要なファイルを除外する方法を試してみました。。import文レベルでの依存関係を調査するツールとしてはpydeps*4を使用しました。
手順
- pydepsを
pip install pydeps
でインストールする。 virtualenv
でPythonの仮想環境を作成する。その中で調査対象のプログラムが動作できるようpip
で必要なパッケージをインストールする。- 調査対象のプログラムのエントリポイント(ここでは
hello.py
)に対してpydeps hello.py --max-bacon=0 --show-deps --noshow > hello.dot
のように実行する。--max-bacon=0
を指定しているのは、デフォルトだと限られた範囲の依存関係しか調査されないため。たとえばFlaskを使っているアプリケーションだと、Flaskへの依存関係しか出力されず、jinja2等への依存関係は表示されない。--show-deps
を指定しているのは、依存関係のグラフに含まれるファイル名を抽出しやすくするため。--noshow
を指定しているのは、WSL2環境ではxdg-utils
によるSVGファイルの表示ができなかったため。
hello.dot
に出力されているPythonファイル名を調べる。出力されているファイルは残し、出力されていないファイルはリネームするなどしてアプリケーションから参照できないようにする。- 仮想環境に残ったファイルのみを使って、アプリケーションが実行可能か確認する。
たとえば https://methane.github.io/flask-handson/start.html#hello-world にあるようなごく単純なFlaskアプリケーションであれば、/lib/python3.8/site-packages/flask/views.py
には直接の依存関係がないことが分かります。virtualenv
で作った環境からviews.py
(と、対応する.pyc
)を削除しても問題なく動作することが確認できました
問題
pydepsはソースコード中のimport
をもとに依存関係を調べるので、実行時に使われないパスを除外できないことの他にも、以下のような問題があると思われます。
eval
で評価される文の中の依存関係を追えない(必要なソースを除外してしまう)- ワイルドカードインポートが使われていると依存関係の調査範囲が分からない(不要なソースが含まれてしまう)