サプライチェーン監査の設計

コミット済みのサプライチェーン監査テストの背後にある検証の原則

サプライチェーン監査は、コミット済みファイルだけからリポジトリの依存関係制御を証明します。 このページでは、監査そのものの信頼性を維持する設計原則を記録します。 騙される可能性のある監査(あるいは何もチェックせずにパスしてしまう監査)は、監査がないことよりも悪質です。 なぜなら、グリーンが未検証の状態を保証してしまうからです。 これらの原則は、この監査とその Docsy の前身に対する敵対的レビューラウンドから生まれたもので、各ラウンドでは制御に違反しているにもかかわらずテストをパスしてしまう入力を探しました。

どのような制御が存在しなぜ必要なのかについては、サプライチェーンセキュリティを参照してください。 監査が PR で失敗した場合の対処方法については、依存関係ドキュメントの監査セクションを参照してください。

原則

各原則は、検証器が嘘をつく方法に対する回答です。 敵対的レビューにより、以前のドラフトでそれらのほとんどについて具体的な事例が発見されました。

  1. コミット済みファイルだけから証明する。 監査はロックファイル、マニフェスト、.npmrcnetlify.toml を読み取ります(ネットワークやインストール済みツリーは読み取りません)。 そのため高速でオフラインであり、検証対象の状態によって左右されることがありません。
  2. パターンの拒否リストではなく、全体の形状を許可リストに登録する。 設定フォーマットに対するすべての拒否リスト正規表現は、最終的に予期しない有効な記法に遭遇しました(引用付き、ドット付き、インラインテーブルの TOML キーはすべて env キー拒否リストをバイパスしました)。 レビュー済みの形状全体(正確なキーセット、正確な値)を固定する方がより強力で、通常はより簡潔です。
  3. 行スキャンではなく、パースする。 フォーマットのパーサーがそのセマンティクスを定義します。 行の正規表現はそれを暗黙的に誤ってモデル化します。 認識できないコンテキストテーブルも Netlify にとっては意味を持ちます。
  4. 正確な固定。接頭辞やフラグのマッチングを行わない。 接頭辞マッチングは、監査が名前で信頼するスクリプトに付加された && npm install ... ライダーを受け入れてしまいます。
  5. 不在時にはクローズドで失敗する。 すべてのカウントチェックにはフロアアサーションが含まれており、空の入力は真空的にパスすることができません。 期待されるフィールドがないエントリは、スキップされるのではなく失敗します。
  6. npm が信頼するアイデンティティにバインドする。 npm はパッケージのアイデンティティをロックキーや version フィールドではなく、resolved レジストリ URL から導出します。 そのため監査は 3 つすべてを結びつけます。 npm が信用しないフィールドだけをチェックすると、npm が作用するミスマッチを見逃してしまいます。
  7. 1つの不変条件に1つのホーム。 2 つのファイルでアサートされたリストはドリフトします。 監査は共有値をその所有モジュールからインポートし(Hugo インストーラーの env オーバーライド名はリビルドヘルパーから取得されます)、そのモジュールのユニットテストが内容を固定します。
  8. レッドファースト。 新しいチェックは、意図的に壊された入力がそれを失敗させた後にのみ信頼されます。 監査の歴史におけるすべてのクロージャは、そのグリーンがカウントされる前にレッドであることが証明されました。 偽のグリーンはレッドよりも悪いのです。
  9. アサーションは期待される条件を命名し、よくある障害については修正方法も命名します。 allowScripts アサーションは依存関係のバンプが移動先とすべきバージョンを命名するため、失敗メッセージがそのまま修正手順になります。
  10. スコープ境界を明示する。 監査が意図的にカバーしない領域(ワークフローファイル、テーマ自体のインストール、ビルド側スクリプト)は監査とドキュメントに明記されており、カバレッジの不在が検証済みカバレッジと誤認されることはありません。
  11. すべてのチェックはその存在価値を示す。 セキュリティは制御の設計とレビューから生まれるのであり、アサーションの蓄積からではありません。 各アサーションは変更のたびにコントリビューターとメンテナーに負担をかけます。 チェックがここに属するのは、レビューでは明らかに検出できないものを検出する場合に限ります。 たとえば、不透明で高い権威性を持つロックファイルや、目視では捉えられないほど難解なセマンティクスです。 制御がすでに実行時にクローズドで失敗する場合、監査はそれを再度検証しません。 チェックの維持コストがその検出価値を上回った場合、それを削減することは弱体化ではなく正しい判断です。

監査における原則

各原則について 1 つの実例を示します。 テストファイルがアサーションの正式な一覧です。

原則監査における実例
コミット済みファイルだけすべての入力はチェックアウトから読み取られ、スイートはネットワークなしで実行されます
全体の形状を許可リストに登録netlify.toml: トップレベルテーブル、ビルドキー、env キーセットは deepEqual で比較されます
行スキャンではなくパースnetlify.toml はアサーションの前に smol-toml でパースされます
正確な固定インストールクロージャスクリプトは assert.equal で比較され、match は使われません
不在時にはクローズドで失敗registryPackages > 0 がフロアとなり、バージョンのないロックエントリは IOC チェックで失敗します
npm が信頼するアイデンティティ各レジストリエントリの resolved URL は自身のパッケージとバージョンを命名する必要があります
1つの不変条件に1つのホームUNSAFE_HUGO_ENVrebuild-hugo-extended.mjs からインポートされます
レッドファースト各ハードニングコミットの PR は、最初に失敗させた壊れた入力を記録しています
アサーションは修正方法を命名allowScripts covers hugo-extended at its locked version X
スコープ境界の明示監査のヘッダーコメントに除外対象の領域が明記されています
チェックの存在価値engines フロアの最小値はレビューで判定され、engine-strict が強制します