TT Lab
はじめる
学ぶ 学習パス コース

ビルドは緑だったのに、あのライブラリを入れたのは誰か

境界を合わせ、今日直せるものだけ残す

TT Labで続きを見る

目標

SBOMを脆弱性データと照合して、実際に影響を受けるものだけを選び出し、「修正バージョンがあるか」と「ユーザーに届くか」という2つの軸で分けて、ポリシーゲートをプログラムとして書きます。

なぜ重要なのか

スキャナーを初めて動かすと、赤い行が数百個出ます。その一覧をそのまま開発チームに送っても、何も起きません。全部は直せないことを、誰もが知っているからです。減らせる場所は2か所です。1つ目、区間の判定が正確である必要があります。修正されたバージョンを使っているのに引っかかる誤検知が混ざると、一覧全体の信頼が崩れます。2つ目、修正バージョンがあるものとないものは別の話です。修正バージョンがあれば今日上げればよく、なければ緩和策と期限を書いてウェイバーで管理する必要があります。この2つを混ぜておくと、会議は「深刻度が高い/低い」だけで回り、何も変わりません。

ステップ

  1. /opt/fixtures/sbom/feeds/advisories.jsonを読んで、/root/adv/01-feed.jsonにデータの形を書きます。
  2. /opt/fixtures/sbom/sbom/paygate-1.4.2.cdx.jsonのcomponentsを平らに展開して、/root/adv/02-components.jsonに書きます。
  3. /root/adv/semver_cmp.pyにバージョン比較器を作ります。
  4. 境界値まで合わせて、影響を受けるものだけを/root/adv/04-findings.jsonに書きます。
  5. 修正バージョンがあるものだけを、/root/adv/05-upgrade-plan.jsonに移します。
  6. ユーザーに届くものとビルドで終わるものを、/root/adv/06-shipped.jsonに分けます。
  7. /root/adv/gate-vuln.pyでポリシーを書いて、結果を/root/adv/07-verdict.jsonに残します。
  8. /root/adv/waivers.jsonのウェイバーを適用して、/root/adv/08-verdict.jsonでもう一度判定します。

参考

データが何を言っているかから読む

/opt/fixtures/sbom/feeds/advisories.jsonを読んで、/root/adv/01-feed.jsonにadvisories・with_fixed・without_fixed・packagesを保存してください。with_fixedは、rangesのeventsにfixedが1つでもあるアドバイザリの数、without_fixedは残り、packagesはaffectedのパッケージ名を辞書順に入れた配列です。

OSVのeventsは、「導入された/修正された/ここまで影響を受ける」を時間順に書いたタイムラインです。fixedのないアドバイザリがあること自体が、このラボの主題です。

何を照合するかを一覧として立てる

/opt/fixtures/sbom/sbom/paygate-1.4.2.cdx.jsonのcomponentsから、name・version・scopeだけを残して、/root/adv/02-components.jsonに、名前の辞書順の配列として保存してください。scopeは、SBOMに書かれた値をそのまま移します。

照合の左側がこの一覧で、右側が脆弱性データです。左側を先に平らに展開しておけば、あとのステップがすべて楽になります。

バージョンを文字列で比較してはいけない理由を、コードで固定する

/root/adv/semver_cmp.pyにcompare(a, b)関数を作ってください。2つの引数はX.Y.Zの形の文字列で、aが小さければ-1、同じなら0、大きければ1をそのまま返します。3つの桁をそれぞれ整数として比較する必要があります。

文字列で比較すると、"1.9.0"が"1.10.0"より大きいと出ます。採点ツールは、そのような組を含めて、いくつもの場合を直接入れてみます。

境界値まで正確に合わせる

/root/adv/semver_cmp.pyの比較で、/opt/fixtures/sbom/sbom/paygate-1.4.2.cdx.jsonと/opt/fixtures/sbom/feeds/advisories.jsonを照合して、実際に影響を受けるものだけを/root/adv/04-findings.jsonにid辞書順の配列として保存してください。各項目はid・package・version・severity・scope・fix_available・fixed_inです。severityはseverity[0].scoreを、scopeはSBOMの値を移します。fixed_inは、そのバージョンが属する区間を閉じるfixedの値で、なければnull、fix_availableはそのブール値です。introducedの"0"は、どのバージョンよりも前を意味する特殊な値です。

区間はintroduced以上fixed未満です。fixedと同じバージョンは、すでに修正されたものです。last_affectedはその日まで確認された上限なので、その値自体はまだ影響を受けます。1つのアドバイザリに区間が2つ以上ある場合もあります。

今日直せるものだけを計画に移す

/root/adv/04-findings.jsonからfix_availableがtrueのものだけを選んで、/root/adv/05-upgrade-plan.jsonにpackage辞書順の配列として保存してください。各項目はpackage・from・to・advisoryで、toはfixed_in、advisoryはアドバイザリidです。

「修正バージョンがあるか」は、深刻度とは別の軸です。今日上げられるものと、今日は上げられないものを先に分けて初めて、会議が終わります。

ユーザーに届くものとビルドで終わるものを分ける

/root/adv/06-shipped.jsonにshippedとdev_onlyを保存してください。どちらもアドバイザリidを辞書順に入れた配列で、scopeがexcludedの発見は、dev_onlyに行きます。

開発専用の依存の欠陥は、デプロイの成果物に載りません。だからといって無視してよいわけではありませんが、ユーザーに届くものと同じ欄に置くと、本当に急ぐものが埋もれます。

ポリシーを人の言葉ではなくプログラムで書く

/root/adv/gate-vuln.pyを作ってください。python3 /root/adv/gate-vuln.py <SBOM> <자료>で呼び出すと、blocking(止めるアドバイザリidの辞書順配列)とverdict("pass"または"fail")を入れたJSON1つを標準出力に出し、止めるものがあれば1で、なければ0で終了します(プレースホルダーは、順にSBOMとデータです)。ポリシーは「デプロイに載り(scopeがrequired)、深刻度がHIGHまたはCRITICALの発見」です。そのあと、python3 /root/adv/gate-vuln.py /opt/fixtures/sbom/sbom/paygate-1.4.2.cdx.json /opt/fixtures/sbom/feeds/advisories.jsonの出力を、/root/adv/07-verdict.jsonに保存してください。

ポリシーがドキュメントにしかないと、人によって読み方が違います。採点ツールは、このスクリプトを別の入力でも呼び出してみます。引っかかるものがない一覧では、0で終了する必要があります。

ウェイバーは直せないものにだけ与える

/root/adv/waivers.jsonにウェイバーを3件書いてください。各項目はid・owner・expires・reasonで、3件はLABHUB-2026-0002(expires 2026-12-31)・LABHUB-2026-0001(expires 2026-12-31)・LABHUB-2026-0007(expires 2026-08-31)で、ownerはすべてpayments-platformです。そのあと、基準日2026-09-11でウェイバーを適用して、/root/adv/08-verdict.jsonにas_of・waived・rejected・blocking・verdictを保存してください。ウェイバーは、基準日に期限が切れておらず、fix_availableがfalseの発見にだけ適用され、拒否されたものは、idとreason("expired"または"fix_available")をid辞書順に入れます。

ウェイバーは、「まだ直せない」を記録する欄であり、「直したくない」を書く欄ではありません。修正バージョンがあるのにウェイバーが通用すれば、そのゲートはその日から飾りです。