SCANOSS CLIでローカルスキャン:インストールからSBOM生成まで

AI開発ツールの普及に伴い、ソースコードに含まれるOSSライセンスリスクへの対応が避けられなくなってきました。SCA(Software Composition Analysis)ツールを使うと、コードベースに混入したOSSコンポーネントを自動検出し、ライセンス違反や既知の脆弱性を可視化できます。

本記事では、SCAツール「SCANOSS」のPython CLI(scanoss-py)を使ったローカルスキャンの手順を紹介します。

この記事でわかること:

  • scanoss-pyのインストールから基本スキャン、結果の読み方
  • scanoss.jsonによる誤検出のチューニング方法
  • CycloneDX / SPDX / CSV形式でのSBOM生成
  • ScanCode Toolkit連携による依存関係スキャン(uv環境での回避策含む)

検証環境

項目内容
OSLinux(WSL2 / devcontainer)
Python3.12
パッケージ管理uv
scanoss-py1.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.1

scanoss-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.90

144ファイルありますが、実際にスキャン対象となるのはソースコードファイルのみです。バイナリ(.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コードの該当行範囲
purlPackage 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

設定適用前後の比較結果です。

ファイルBeforeAfter
app.pyollama-workbench (18%)マッチなし(removeで除外)
Dockerfileip-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 ./src

bom.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.csv

3形式の使い分けは以下の通りです。

形式用途
CycloneDXDependency Track等のSBOM管理ツールへの連携
SPDX-Liteライセンスコンプライアンス管理(業界標準仕様)
CSVExcelやスプレッドシートでの手動レビュー

注意点として、CycloneDX出力は拡張子を.xmlにしても実際の出力はJSON形式です。XML形式での出力が必要な場合は別途変換が必要です。

依存関係スキャン

scanoss-pyは、requirements.txtpyproject.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.0

uv環境での注意点

ScanCode Toolkitはuv.lockに対応していません(GitHub Issue #4501、2026年2月時点でOpen)。サポート対象のパッケージマニフェスト形式は公式ドキュメントで確認できます(requirements.txtpyproject.tomlpoetry.lockPipfile.lock等は対応済み)。

uv環境で依存関係をスキャンする場合、uv exportrequirements.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.txtpyproject.toml等のマニフェストファイルを自動検出してパースします。個別にファイルを指定する必要はありません。

--sc-commandにはscancode実行ファイルの絶対パスを指定します。uv run scancodeのような形式は内部のsubprocess呼び出しの都合で使えません。

depサブコマンドとscan --dependenciesの違いは以下の通りです。

depscan --dependencies
SCANOSS API送信なしあり
ライセンス情報の付与なしあり
用途事前確認・デバッグフルSBOM生成

フィンガープリントの活用

fingerprintサブコマンドを使うと、スキャンとAPI送信を分離できます。

# フィンガープリントの生成(オフラインでもOK)
scanoss-py fingerprint -o fingerprint.wfp ./src

# 後からスキャン(ネットワーク接続時)
scanoss-py scan --wfp fingerprint.wfp -o results.json

ネットワークに接続できない環境でフィンガープリントだけ先に生成し、接続時にスキャンを実行するワークフローに活用できます。

運用上のポイント

検証を通じて得られた実践的なポイントをまとめます。

推奨ワークフロー

  1. 初回スキャンを設定なしで実行し、検出結果を確認する
  2. 誤検出を確認し、scanoss.jsonを作成してチューニングする
  3. チューニング後の結果に問題がなければ、SBOMを生成する
  4. 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 ./src

API 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等)を検討することで、プルリクエスト単位での自動チェックが可能になります。

参考資料

関連リンク

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です