はじめに
第1回では、生成AIによってコードを書く速度が上がる一方、依存パッケージのリスクを継続的に把握する仕組みが追いついていないという問題を整理した。
コード生成が速くなったとしても、それだけでは安心できない。
依存ライブラリ、静的解析結果、既知脆弱性。それぞれの情報を継続的に追跡できなければ、リスク管理は結局人手に依存することになる。
そこで今回は、その受け皿として検討していた IBM Concert Protect を実際に触ってみることにした。
対象は GitHub Actions CI が生成した3種類のセキュリティ成果物である。
まず確認したかったのは自動化ではない。
どの成果物が取り込めて、どの成果物が取り込めないのか。
成果物そのものの問題と、自動化設定の問題を切り分けるため、最初は手動投入から始めることにした。
Concert Protect のデータ構造:今回確認できたこと
手動投入を進める中で、Concert Protect のデータの扱い方について次のことが確認できた。
単一のファイルを投入してすべての情報が揃うわけではなく、成果物の種別ごとに独立した入力経路がある。今回の検証で取り込みに成功した経路は以下の4つだ。
Concert Protect(今回確認した入力経路)
├── Application 登録(UI操作)
│ → Application / Repository Topology
│
├── Package SBOM(concert-package-sbom.json)
│ → Package Inventory
│ → Package Risk
│ → License 情報
│
├── SAST(python.sarif)
│ → Static Security Findings
│
└── CVE(trivy-image.json)
→ Vulnerability Dashboard
実際に投入してみると、SBOM を入れても CVE データは現れず、SAST を入れても Package Inventory は生成されなかった。各データソースは独立して管理され、Concert Protect 上で関連付けられる構造になっている。
最初にこの構造を把握せずに投入を始めたため、「投入できているのに何も表示されない」という場面が生じた。
投入した成果物と結果
GitHub Actions CI ワークフローから以下の成果物を取得し、Concert Protect の UI から手動で投入した。
| 成果物ファイル | 生成ツール | Concert 投入種別 |
|---|---|---|
concert-package-sbom.json |
cyclonedx-py + 変換スクリプト |
Package SBOM |
python.sarif |
GitHub CodeQL | SAST |
trivy-image.json |
Trivy 0.70.0(コンテナスキャン) | Image Scan |
sbom.json |
cyclonedx-py(標準出力) |
Package SBOM |
trivy-fs.json |
Trivy 0.70.0(ファイルシステムスキャン) | Image Scan |
投入順序は Application 登録を先に行い、その後 Package SBOM → SAST → CVE の順で進めた。
成功した経路
Package SBOM:concert-package-sbom.json
Concert UI の Upload → Package SBOM から concert-package-sbom.json を投入したところ、Package Inventory に 76 パッケージが展開され、Package Risk と License 情報が表示された。
このファイルは cyclonedx-py が出力した sbom.json を、そのままでは取り込めなかったため Concert 向けに整形したものだ。
成功した SBOM と失敗した SBOM を見比べながら差分を確認し、自作した scripts/convert_sbom_for_concert.py で必要な項目だけを補完している。
具体的には、
-
metadata.component.typeをapplicationに設定 -
metadata.componentに VCS 参照(リポジトリURL)を追加 - 依存コンポーネントの
typeをframeworkに変換
を行っている。
興味深かったのは、CycloneDX 1.6 形式であることだけでは十分ではなかった点だ。
フォーマットは合っている。
それでも取り込まれない。
Concert は JSON スキーマだけでなく、アプリケーションと依存関係の表現方法にも一定の期待値を持っているように見えた。
後から振り返ると、この変換は単なる JSON 変換というより、Python パッケージの一覧だった SBOM に「Application」というルート要素を与える作業だった。
Concert Protect はアプリケーション単位でリスクを追跡する。
そのため依存ライブラリの集合だけでは十分ではなく、それらを利用する主体も SBOM 内に表現する必要があるように見える。
この変換によって CycloneDX 1.6 形式を維持したまま取り込みに成功した。
取り込み後は Package Inventory が生成され、依存ライブラリごとのリスクスコア、公開時期、ライセンス情報が表示された。
図:Package Inventory 画面。パッケージごとのリスクスコア、公開時期、ライセンス情報が表示される。
興味深かったのは、脆弱性の有無だけでなく、古いパッケージや管理状態もリスク要因として扱われていた点だ。SBOM は単なる部品一覧ではなく、リスク評価の入口として扱われているように見えた。
SAST:python.sarif
Upload → SAST から python.sarif(GitHub CodeQL の標準出力)を投入したところ、SAST Exposure が表示された。
変換は不要だった。CodeQL の標準 SARIF 2.1.0 形式はそのまま取り込み可能だった。
取り込み後は、CodeQL が検出したルールごとの結果が Concert Protect 上で可視化された。今回の検証では以下のルールが表示されている。
py/missing-call-to-initpy/empty-exceptpy/import-and-import-frompy/ineffectual-statementpy/unused-global-variable

図:SAST Exposure 画面。CodeQL のルールごとに発見優先度とリスク点数が表示される。
単純な件数表示だけではなく、優先度や発生傾向も合わせて確認できた。
Image Scan:trivy-image.json
Upload → Image Scan から trivy-image.json を投入したところ、CVE Dashboard が生成された。
Trivy のコンテナスキャン出力(SchemaVersion: 2、ArtifactType: container_image)はそのまま取り込まれた。
取り込み後は、検出された脆弱性ごとの優先度、CVSS スコア、修正可能なバージョンなどが表示された。今回の環境では Critical を含む複数の脆弱性が検出されており、修正可能なものと未修正のものを区別して確認できる。

図:CVE Dashboard 画面。優先度別の脆弱性件数と修正可用性が表示される。
単に CVE の一覧を表示するだけでなく、「どこから対応を始めるべきか」を判断する材料が提供されているように見えた。
Concert Protect が可視化した内容
3種類の成果物を投入すると、Concert Protect 上ではそれぞれ別々の情報として管理されるだけではなく、同じ Application に集約されて表示された。
以下は今回の検証環境で実際に表示されたダッシュボードだ。

図:SBOM、SARIF、Trivy の結果を投入後の Concert Protect ダッシュボード。依存ライブラリ、静的解析結果、既知脆弱性を単一の Application に集約して表示できることを確認した。
Package Risk は SBOM から生成される。SAST Exposure は CodeQL の SARIF 結果から生成される。CVE Dashboard は Trivy のコンテナスキャン結果から生成される。それぞれ入力経路は異なるが、最終的には同じアプリケーションのリスク情報として管理される。
今回確認したかったのはまさにここだった。SBOM、SAST、脆弱性情報を別々に確認するのではなく、アプリケーション単位で集約して追跡できるのか。その点については、期待した形にかなり近い結果が得られた。
依存ライブラリのリスク、静的解析結果、既知脆弱性が個別のレポートとして存在するのではなく、同一の Application に集約されていることが確認できる。どのリポジトリの、どのバージョンのアプリケーションに対するリスクなのかを横断的に追跡できるようになった。
失敗した経路
sbom.json(標準出力)
cyclonedx-py が直接出力した sbom.json を Package SBOM として投入したところ、次のエラーが返った。
入力データが必要な形式に一致しないため、ファイルの解析に失敗しました。
CycloneDX 1.6 であることは確認していたため、この時点では何が足りないのか全く分からなかった。
フォーマットは CycloneDX 1.6 であり、concert-package-sbom.json と同じ仕様だ。しかし Concert は取り込みを拒否した。
取り込みに成功した concert-package-sbom.json と比較すると、前述の3項目(metadata.component.type、VCS参照、コンポーネントの type)に差異があった。どの差異が直接原因かは、今回の検証では項目ごとに個別に切り分けていないため特定できていない。
trivy-fs.json(ファイルシステムスキャン)
trivy-fs.json を Image Scan として投入したところ、同じエラーが返った。
成功した trivy-image.json と比較すると、次の差異があった。
| フィールド | trivy-image.json(成功) | trivy-fs.json(失敗) |
|---|---|---|
ArtifactType |
container_image |
filesystem |
Metadata |
OS / ImageID / DiffIDs などあり | これらフィールドが欠落 |
Results[].Class |
os-pkgs / lang-pkgs
|
lang-pkgs のみ |
Vulnerabilities |
あり | 空 |
Concert の Image Scan 取り込みは ArtifactType: container_image を前提としており、ArtifactType: filesystem は形式不一致になると推定される。Vulnerabilities フィールドが空であることも複合的な要因として残る可能性がある。
Trivy Filesystem Scan 結果を Concert に投入する正式な data_type が存在するかどうかは、現時点では確認できていない。
検証結果のまとめ
| 成果物 | 結果 | Concert 側の反映 |
|---|---|---|
concert-package-sbom.json |
成功 | Package Inventory(76パッケージ)・Package Risk・License |
python.sarif |
成功 | SAST Exposure |
trivy-image.json |
成功 | CVE Dashboard |
sbom.json |
失敗 | フォーマット不一致エラー |
trivy-fs.json |
失敗 | パースエラー |
今回の検証で分かったのは、Concert Protect が「SBOM を投入すればすべてのリスクを自動的に可視化してくれるツール」ではないということだった。
Package Inventory、SAST、CVE はそれぞれ独立した入力経路を持っており、対応する成果物を個別に投入する必要がある。
その一方で、必要な成果物さえ揃えば、Application を中心にリスク情報を集約できることも確認できた。
今回行ったのは手動投入だが、確認したかったのは Concert Protect の画面操作ではない。
GitHub Actions が生成した成果物を使って、アプリケーションのリスクを一か所に集約できるのか。
その問いに対しては、「できる。ただし成果物ごとに適切な形式と入力経路が必要」というのが今回の結論である。
同じ検証をやろうとして詰まった箇所
実際に手を動かして詰まった箇所を3点記録しておく。
Application を先に登録しないとデータが紐付かない: SBOM から先に投入したところ、Package Inventory は表示されたが Application との関連付けがされていなかった。Application 登録 → Package SBOM → SAST → CVE の順で投入する必要があった。
cyclonedx-py の標準出力はそのまま使えなかった: フォーマットは同じ CycloneDX 1.6 なのにエラーが返った。Concert 向けの変換スクリプトを通したファイルだけが取り込まれた。変換で変わるのは metadata.component.type、VCS参照、コンポーネント type の3点だが、どれが決定打かは今回の検証では切り分けていない。
同じ Trivy でもスキャン種別で結果が分かれた: コンテナスキャンは通ったがファイルシステムスキャンは弾かれた。ツールのバージョンは同じ 0.70.0 で、違いは ArtifactType の値だった。
連載一覧
次回予告
今回は成果物を手動で投入し、どこまで可視化できるのかを確認した。
では、その成果物はどこで作られているのだろうか。
第3回では GitHub Actions CI パイプラインに戻り、SBOM・SAST・コンテナスキャン結果がどのように生成されているのかを整理する。
CodeQL、Trivy、そして SBOM 変換スクリプトがどのように連携しているのかを追いかけていく。
検証環境
- IBM Concert: 3.0.x
- CycloneDX: 1.6(
cyclonedx-py7.4.0 /cyclonedx-python-lib11.12.0) - Trivy(GitHub Actions 側): 0.70.0
- CodeQL: GitHub Actions で実行(GitHub 提供)
参考:
https://www.ibm.com/docs/en/concert/3.0.x?topic=vulnerability-supported-scan-formats

