境界を合わせ、今日直せるものだけ残す
目標
SBOMを脆弱性データと照合して、実際に影響を受けるものだけを選び出し、「修正バージョンがあるか」と「ユーザーに届くか」という2つの軸で分けて、ポリシーゲートをプログラムとして書きます。
なぜ重要なのか
スキャナーを初めて動かすと、赤い行が数百個出ます。その一覧をそのまま開発チームに送っても、何も起きません。全部は直せないことを、誰もが知っているからです。減らせる場所は2か所です。1つ目、区間の判定が正確である必要があります。修正されたバージョンを使っているのに引っかかる誤検知が混ざると、一覧全体の信頼が崩れます。2つ目、修正バージョンがあるものとないものは別の話です。修正バージョンがあれば今日上げればよく、なければ緩和策と期限を書いてウェイバーで管理する必要があります。この2つを混ぜておくと、会議は「深刻度が高い/低い」だけで回り、何も変わりません。
ステップ
/opt/fixtures/sbom/feeds/advisories.jsonを読んで、/root/adv/01-feed.jsonにデータの形を書きます。/opt/fixtures/sbom/sbom/paygate-1.4.2.cdx.jsonのcomponentsを平らに展開して、/root/adv/02-components.jsonに書きます。/root/adv/semver_cmp.pyにバージョン比較器を作ります。- 境界値まで合わせて、影響を受けるものだけを
/root/adv/04-findings.jsonに書きます。 - 修正バージョンがあるものだけを、
/root/adv/05-upgrade-plan.jsonに移します。 - ユーザーに届くものとビルドで終わるものを、
/root/adv/06-shipped.jsonに分けます。 /root/adv/gate-vuln.pyでポリシーを書いて、結果を/root/adv/07-verdict.jsonに残します。/root/adv/waivers.jsonのウェイバーを適用して、/root/adv/08-verdict.jsonでもう一度判定します。
参考
- 作業はすべて
/root/advの下で行います。最初にmkdir -p /root/advを実行してください。 - 区間は
introduced以上fixed未満です。fixedと同じバージョンは、すでに修正されたものです。 introducedの"0"は、「どのバージョンよりも前」を意味する特殊な値です。last_affectedは、その値まで影響を受けるという意味なので、境界の含み方がfixedと逆です。- 基準日は
2026-09-11に固定します。dateを読んで使うと、明日は別の答えが出ます。 - よくあるミスは、バージョンを文字列で比較すること(
"1.9.0" > "1.10.0"が真になります)と、1つのアドバイザリに区間が2つ以上あるときに、最初の区間だけを見て終えることです。 - パッケージ名とアドバイザリ番号は、実習用に作り上げたものです。
データが何を言っているかから読む
/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辞書順に入れます。
ウェイバーは、「まだ直せない」を記録する欄であり、「直したくない」を書く欄ではありません。修正バージョンがあるのにウェイバーが通用すれば、そのゲートはその日から飾りです。