AI開発ツールの普及に伴い、ソースコードに含まれるOSSライセンスリスクへの対応が避けられなくなってきました。SCA(Software Composition Analysis)ツールを使うと、コードベースに混入したOSSコンポーネントを自動検出し、ライセンス違反や既知の脆弱性を可視化できます。
本記事では、SCAツール「SCANOSS」のPython CLI(scanoss-py)を使ったローカルスキャンの手順を紹介します。
この記事でわかること:
- scanoss-pyのインストールから基本スキャン、結果の読み方
- scanoss.jsonによる誤検出のチューニング方法
- CycloneDX / SPDX / CSV形式でのSBOM生成
- ScanCode Toolkit連携による依存関係スキャン(uv環境での回避策含む)
検証環境
| 項目 | 内容 |
|---|---|
| OS | Linux(WSL2 / devcontainer) |
| Python | 3.12 |
| パッケージ管理 | uv |
| scanoss-py | 1.45.1 |
| API Key | なし(匿名 / OSSKB パブリック API) |
今回はAPI Keyなし(無料のOSSKBパブリックAPI)で検証しています。小〜中規模のプロジェクトであれば、API Keyなしでも十分に利用できます。
インストール
pipまたはuvでインストールできます(PyPI: scanoss)。
# pip の場合
pip install scanoss
# uv の場合(dev依存として追加)
uv add --dev scanossインストール後、バージョンを確認します。
$ scanoss-py version
Version: 1.45.1scanoss-py --helpでサブコマンド一覧を確認できます。主なサブコマンドは以下の通りです。
| サブコマンド | 説明 |
|---|---|
scan | ソースコードのスキャン |
fingerprint | フィンガープリント(WFP)の生成 |
dependencies | 依存関係のスキャン |
convert | スキャン結果のフォーマット変換 |
file_count | ファイル数・サイズのサマリー |
基本スキャン
ファイル数の確認
スキャン前に、対象ディレクトリのファイル構成を確認できます。
$ scanoss-py file_count ./src
Found 144 files with a total size of 7.16 MB.
extension,count,size(MB)
.py,47,0.20
.pyc,44,0.39
.html,21,0.07
.png,21,5.90144ファイルありますが、実際にスキャン対象となるのはソースコードファイルのみです。バイナリ(.png)や.pycは自動的に除外されます。
スキャンの実行
$ scanoss-py scan -o results.json ./src実行すると、対象ファイルのフィンガープリントを生成し、OSSKB(Open Source Knowledge Base)のナレッジベースと照合します。OSSKBには2億7,600万以上のURL[1]がインデックスされており、OSSファイル1億以上[1]、コード行数3兆行以上[1]をカバーしています。今回の検証では48ファイルのスキャンが約5秒で完了しました。
スキャン結果の読み方
結果はJSON形式で出力されます。各ファイルごとにマッチ情報が記録されます。
{
"src/app.py": [
{
"id": "snippet",
"component": "some-oss-project",
"matched": "18%",
"lines": "24-31",
"oss_lines": "513-520",
"purl": ["pkg:github/owner/repo"],
"licenses": [{ "name": "MIT", "copyleft": "no" }],
"url": "https://github.com/owner/repo",
"status": "pending"
}
]
}主要フィールドの意味は以下の通りです。
| フィールド | 説明 |
|---|---|
id | マッチ種別。none(マッチなし)/ snippet(部分一致)/ file(完全一致) |
matched | マッチ率 |
lines / oss_lines | 自分のコード / OSSコードの該当行範囲 |
purl | Package URL(コンポーネントの一意識別子) |
licenses | 検出されたライセンス情報(copyleftフラグ付き) |
status | レビュー状態(pending = 未レビュー) |
今回の検証結果は以下の通りです。
| 項目 | 件数 |
|---|---|
| スキャン対象 | 48ファイル |
| マッチなし(id=none) | 43 |
| スニペットマッチ(id=snippet) | 5 |
| フルファイルマッチ(id=file) | 0 |
自社開発のコードなので、フルファイルマッチ(OSSファイルの完全コピー)は0件。5件のスニペットマッチが検出されましたが、いずれもDockerfileやpytestの定型パターンによるもので、実質的な誤検出でした。
scanoss.jsonで検出結果をチューニングする
初回スキャンで誤検出が含まれる場合、scanoss.jsonで検出結果を制御できます(公式ドキュメント)。
設定ファイルの構成
{
"bom": {
"include": [
{
"purl": "pkg:github/owner/repo",
"comment": "宣言済みコンポーネントとして登録"
}
],
"remove": [
{
"path": "src/app.py",
"purl": "pkg:github/owner/repo",
"comment": "誤検出のため除外"
}
]
},
"skip": {
"patterns": ["*.pyc", "__pycache__/**"]
}
}| セクション | 効果 |
|---|---|
bom.include | スキャン時に追加コンテキストとしてPURLをAPIに送信する[2] |
bom.remove | スキャン後の結果から特定PURLを除去する[2] |
skip.patterns | マッチしたファイルをスキャン対象から除外する[2] |
設定を適用してスキャン
$ scanoss-py scan --settings /absolute/path/to/scanoss.json -o results.json ./src設定適用前後の比較結果です。
| ファイル | Before | After |
|---|---|---|
| app.py | ollama-workbench (18%) | マッチなし(removeで除外) |
| Dockerfile | ip-query-system (62%) | minimage (39%)(includeにより次候補に変化) |
scanoss.jsonの注意点
検証を通じて、いくつか注意すべき点が見つかりました。
--settingsには絶対パスを指定する
相対パスを指定すると、カレントディレクトリではなくスキャン対象ディレクトリからの相対パスとして解決されます。
# NG: パスが「src/path/to/scanoss.json」と結合される
scanoss-py scan --settings path/to/scanoss.json ./src
# OK: 絶対パスなら問題なし
scanoss-py scan --settings /home/user/scanoss.json ./srcbom.removeはpathとpurlの完全一致が必要
スキャン結果のpurlと設定ファイルのpurlが一致しないと除外されません。必ず初回スキャン結果のpurlを確認してから設定してください。
bom.includeはマッチを消すのではなく「宣言済み」にする
includeに登録しても、スキャン結果からマッチ自体が消えるわけではありません。該当コンポーネントが「宣言済み」として扱われ、スキャン結果は次候補のコンポーネントに変化する場合があります。
SBOM生成
スキャン結果を業界標準のSBOM形式に変換できます。
# CycloneDX
scanoss-py convert -i results.json -f cyclonedx -o sbom.cdx.json
# SPDX-Lite
scanoss-py convert -i results.json -f spdxlite -o sbom.spdx.json
# CSV
scanoss-py convert -i results.json -f csv -o results.csv3形式の使い分けは以下の通りです。
| 形式 | 用途 |
|---|---|
| CycloneDX | Dependency Track等のSBOM管理ツールへの連携 |
| SPDX-Lite | ライセンスコンプライアンス管理(業界標準仕様) |
| CSV | Excelやスプレッドシートでの手動レビュー |
注意点として、CycloneDX出力は拡張子を.xmlにしても実際の出力はJSON形式です。XML形式での出力が必要な場合は別途変換が必要です。
依存関係スキャン
scanoss-pyは、requirements.txtやpyproject.toml等から依存パッケージを検出する機能も備えています。ただし、この機能にはScanCode Toolkitが別途必要です。
セットアップ
# 1. scancode-toolkit のインストール
pip install scancode-toolkit
# または
uv add --dev scancode-toolkit
# 2. libgomp1 のインストール(Debian系のslimイメージの場合)
sudo apt-get install -y libgomp1
# 3. 動作確認
scancode --version
# → ScanCode version: 32.5.0uv環境での注意点
ScanCode Toolkitはuv.lockに対応していません(GitHub Issue #4501、2026年2月時点でOpen)。サポート対象のパッケージマニフェスト形式は公式ドキュメントで確認できます(requirements.txt、pyproject.toml、poetry.lock、Pipfile.lock等は対応済み)。
uv環境で依存関係をスキャンする場合、uv exportでrequirements.txtに変換する必要があります。
uv export --format requirements-txt --no-hashes --no-emit-workspace -o requirements.txtなお、--no-devオプションを付けると、直接依存がすべてdev依存のプロジェクトでは空ファイルになります。必要に応じてオプションを調整してください。
依存関係スキャンの実行
# dep サブコマンド(API送信なし、ローカルのみ)
scanoss-py dep \
--sc-command /path/to/.venv/bin/scancode \
-o dependencies.json ./src
# scan --dependencies(通常スキャン + 依存関係スキャン)
scanoss-py scan --dependencies \
--sc-command /path/to/.venv/bin/scancode \
-o results.json ./srcディレクトリを指定すると、ScanCode Toolkitが配下のrequirements.txtやpyproject.toml等のマニフェストファイルを自動検出してパースします。個別にファイルを指定する必要はありません。
--sc-commandにはscancode実行ファイルの絶対パスを指定します。uv run scancodeのような形式は内部のsubprocess呼び出しの都合で使えません。
depサブコマンドとscan --dependenciesの違いは以下の通りです。
dep | scan --dependencies | |
|---|---|---|
| SCANOSS API送信 | なし | あり |
| ライセンス情報の付与 | なし | あり |
| 用途 | 事前確認・デバッグ | フルSBOM生成 |
フィンガープリントの活用
fingerprintサブコマンドを使うと、スキャンとAPI送信を分離できます。
# フィンガープリントの生成(オフラインでもOK)
scanoss-py fingerprint -o fingerprint.wfp ./src
# 後からスキャン(ネットワーク接続時)
scanoss-py scan --wfp fingerprint.wfp -o results.jsonネットワークに接続できない環境でフィンガープリントだけ先に生成し、接続時にスキャンを実行するワークフローに活用できます。
運用上のポイント
検証を通じて得られた実践的なポイントをまとめます。
推奨ワークフロー
- 初回スキャンを設定なしで実行し、検出結果を確認する
- 誤検出を確認し、scanoss.jsonを作成してチューニングする
- チューニング後の結果に問題がなければ、SBOMを生成する
- scanoss.jsonをリポジトリに含め、CI/CDでの継続的スキャンに移行する
デフォルトの設定ファイル探索
scanoss-pyは、--settingsを指定しなくても、スキャン対象ディレクトリ直下のscanoss.jsonを自動的に読み込もうとします。リポジトリのルートにscanoss.jsonを配置しておけば、オプション指定なしでチューニング済みのスキャンを実行できます。
API Keyなしとありの違い
今回の検証はAPI Keyなし(OSSKBパブリックAPI)で実施しています。小〜中規模のプロジェクトであればAPI Keyなしで十分ですが、本番運用ではAPI Keyの利用を検討してください。
| 項目 | API Keyなし | API Keyあり |
|---|---|---|
| 基本スキャン | 利用可能 | 利用可能 |
| 可用性保証 | なし | SLA保証あり |
| スループット保証 | なし | 保証あり |
| ナレッジベース更新 | 四半期ごと | リアルタイム同期 |
API Keyありでスキャンする場合は、--keyオプションを指定します。
scanoss-py scan --key YOUR_API_KEY -o results.json ./srcAPI Keyの取得にはSCANOSSとの契約が必要です。CI/CD環境で利用する場合は、GitHub Actionsのsecrets.SCANOSS_API_KEYのようにシークレットとして管理してください。
今回の検証規模(48ファイル)では、API Keyなしでもレート制限に抵触せず、スキャン速度も5秒程度と快適でした。なお、具体的なレート制限値は公式ドキュメントに記載されていないため、大規模プロジェクトでの利用時はSCANOSSへの問い合わせを推奨します。
まとめ
scanoss-pyを使ったローカルスキャンの手順を一通り紹介しました。
| 機能 | ポイント |
|---|---|
| 基本スキャン | API Keyなしで即実行可能。バイナリは自動除外 |
| scanoss.json | 誤検出のチューニングに必須。purlの完全一致と絶対パス指定に注意 |
| SBOM生成 | CycloneDX / SPDX / CSVの3形式に対応 |
| 依存関係スキャン | ScanCode Toolkitが別途必要。uv.lockは未対応 |
ローカルスキャンで動作を確認した後は、CI/CDパイプラインへの統合(GitHub ActionsのSCANOSS Code Scan Action等)を検討することで、プルリクエスト単位での自動チェックが可能になります。


