はじめに
こんにちは!SBOMツールを調査中のなーがです。前回に引き続きSCANOSSについてみていきます。今回はPythonのSDK「scanoss.py」を使ってみたのでインストール方法や機能について書きます。SBOMについてよく分からないという方は、まずこちらの記事を読んでみてください。
- SCANOSSについて
- 検証用GUIツール「SBOM Workbench」
- PythonのSDK「scanoss.py」 ← 今回
インストール
Pythonの仮想環境を作成し、 Python Scanner
をインストールします。
https://www.softwaretransparency.org/download
コマンドオプション
コマンドオプションは以下の通りです。scan
だけでなく、依存関係を含めたスキャンやフォーマット変換が用意されています。
Fingerprinting生成(オプション)
スキャンコマンドの実行中に自動的に行われます。ここで生成されたFingerprintがサーバーに送信されます。
fingerprint.wfp
file=6e588ad70d32289ba8473f7e24716b8f,476,/express-app/views/index.ejs
5=a0e44c67
6=50cf271f,688f9bfe
10=3a8d7c3a
12=dac0aa3f
14=c6b5efb0
16=7af50e1f
file=31c693a880e86ce5a534fb03d151b4f4,2391,/express-app/index.js
5=40daea7b,ccb8356e
9=5800d9dc
10=b9ccb2d2,0db59e12
12=d59964a0
14=f636b37b
17=1db7ed12
19=d73a22b6,a8f419e7
20=8197b0b1,6b8f68ef
22=f1421678
24=fdd6d858
26=78f246d7,1fc66e08
28=72bd1285
32=f24bbde2,ac04acee
...
最初のフィールドはスキャンするファイルの MD5 を含む文字列になっています。この例では下記になります。
6e588ad70d32289ba8473f7e24716b8f
次にファイルサイズ、
476
最後にファイル名が表示されています。
/express-app/views/index.ejs
その下は行番号とソースコードの抽象化を表すフィンガープリントによって作成された行のリストになります。
5=a0e44c67
6=50cf271f,688f9bfe
10=3a8d7c3a
12=dac0aa3f
14=c6b5efb0
16=7af50e1f
このように、フィンガープリントからソースコードを再構築することはほとんど不可能であることがわかります。
スキャン実行
下記のコマンドを実行します。スキャン中はプログレスバーが表示されます。スキャンにかかる時間はプロジェクトのファイル数が多くなるにつれて長くなります。
scanoss-py scan -o scan-output.json スキャン対象のフォルダをパスで指定
フォーマットを指定しない場合は、下記のようにJSON形式で出力されます。出力内容としては、一致したコンポーネント名、バージョン、パール、ライセンス、著作権などの情報が含まれます。
{
"ag-api//function_app.py": [
{
"id": "none",
"server": {
"kb_version": {
"daily": "24.09.26",
"monthly": "24.08"
},
"version": "5.4.8"
}
}
],
"xpress-app//index.js": [
{
"id": "none",
"server": {
"kb_version": {
"daily": "24.09.26",
"monthly": "24.08"
},
"version": "5.4.8"
}
}
],
"xpress-app//node_modules//@azure-rest//core-client//dist//browser//apiVersionPolicy.d.ts": [
{
"component": "@azure-rest/core-client",
"file": "package/dist/browser/apiVersionPolicy.d.ts",
"file_hash": "6026cf8d3f84e321eaa68250d98048be",
"file_url": "<https://api.osskb.org/file_contents/6026cf8d3f84e321eaa68250d98048be>",
"id": "file",
"latest": "2.2.1-alpha.20240802.1",
"licenses": [
...
フォーマット指定
オプション --format
(または -f
)を付けることで、下記の3パターンで出力できます。
- RAW:plain(デフォルト)
- SPDXLite:spdxlite
- CycloneDX:cyclonedx
- CSV: csv
以下はフォーマットとして CycloneDX
を指定してスキャンを実行しています。
依存関係のスキャン
pip install scancode-toolkit
コンポーネント検索
APIキーを指定して、GitHubから vue
を含むコンポーネントを検索してみます。 vue
として登録されているコンポーネントがPURL(Package URL)、URLとともに出力されました。
APIキーは、こちらからトライアルキーをリクエストする必要があります。
Dockerイメージによる実行
Dockerイメージをpullします。
docker pull ghcr.io/scanoss/scanoss-py:latest
PythonのCLIはDockerイメージから公開されており、以下の方法で実行できます。
現在のフォルダをスキャンするには下記のように指定します。
docker run -it -v "$(pwd)":"/scanoss" ghcr.io/scanoss/scanoss-py scan .
また、 -o
オプションで結果をファイルに出力することもできます。
docker run -it -v "$(pwd)":"/scanoss" ghcr.io/scanoss/scanoss-py scan -o results.json .
さらに、依存関係のスキャンをサポートするために、このコンテナには scancode-toolkit
が含まれています。 依存関係をスキャンするには以下を実行します。
docker run -it -v "$(pwd)":"/scanoss" ghcr.io/scanoss/scanoss-py scan -D .
GitHub Actions
scanoss.py
をGitHub Actionsで実行してみます。
スキャン対象のリポジトリにワークフローを作成し、生成されたSBOMを確認します。
「Actions」から「set up a workflow yourself」をクリックします。
ファイル名(今回はscan.yml)、下記のワークフローを記載して「Commit changes…」をクリックします。ここではSCANOSSのdockerイメージからscanoss.py
を実行します。
name: SCANOSS CI Scan
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Scan
run: docker run -v "$(pwd)":"/scanoss" ghcr.io/scanoss/scanoss-py scan --output output.json .
- uses: actions/upload-artifact@v3
with:
name: output.json
path: output.json
今回は master
ブランチに追加せず、新しいブランチを作成したいので、「Create a new branch for this commit and start a pull request」を選択して「Propose changes」をクリックします。
(master(main)ブランチに直接追加したい場合は「Commit directly to the master(main) branch」を選択します)
「Create pull request」をクリックします。
Pull Requestが発行されるとGitHub Actionsが実行されるので、実行結果を確認します。「Actions」からワークフロー(今回は Create scanoss.yml
)をクリックします。
Actionsの実行結果が表示されます。
ダウンロードボタンをクリックすると、出力結果の output.json
をダウンロードできます。
ダウンロードされたZipファイルを解凍し、 output.json
を確認すると、下記のようなスキャン結果が出力されていることが分かります。
{
"express-app/index.js": [
{
"id": "none",
"server": {
"kb_version": {
"daily": "24.09.27",
"monthly": "24.08"
},
"version": "5.4.8"
}
}
],
"express-app/public/js/app.js": [
{
"component": "juanzi",
"file": "package/index.js",
"file_hash": "4c0e7d3ec9dd03fd7830e56642ab77ff",
"file_url": "<https://api.osskb.org/file_contents/4c0e7d3ec9dd03fd7830e56642ab77ff>",
"id": "file",
"latest": "1.0.0",
"licenses": [
{
"checklist_url": "<https://www.osadl.org/fileadmin/checklists/unreflicenses/ISC.txt>",
"copyleft": "no",
"name": "ISC",
"osadl_updated": "2024-09-20T09:32:00+0000",
"patent_hints": "no",
"source": "component_declared",
"url": "<https://spdx.org/licenses/ISC.html>"
}
],
"lines": "all",
"matched": "100%",
"oss_lines": "all",
"purl": [
"pkg:npm/juanzi"
],
"release_date": "2019-11-18",
...
さいごに
今回はPythonのSDK「scanoss.py」を使ってみたのでインストール方法や機能について書きました。今後も業務で学習した内容をブログとして投稿しようと思います。