intakelog は「開発マシンに何を・いつ・どこから取り込んだか」を記録する CLI。脆弱性の判定は自分でやらず osv-scanner に任せ、自分は台帳と経路の横断収集とレポートに専念する。この資料は、そのシステム構成・利用者が使い始めるまでの流れ・出力のイメージをまとめたもの。
lockfile と SBOM が答えられるのは「今何が入っているか」だけ。サプライチェーン事案が起きた日に実際に必要になる情報は、そこには入っていない。
| 知りたいこと | lockfile / SBOM | intakelog |
|---|---|---|
| 今どの版が入っているか | 答えられる | 扱わない(重複させない) |
| いつ入れたか | 持っていない | 台帳に記録 |
| どこから来たか(実 URL・ハッシュ) | レジストリ経由のみ部分的 | 台帳に記録 |
| なぜ入れたか | 持っていない | 台帳に記録 |
| npm 以外(OS のパッケージ管理・clone・シェル一行) | 対象外 | 台帳に記録 |
2026 年 8 月 4 日の npm 大規模侵害(keyv / cacheable 系)で、「攻撃開始時刻より後に install したか」を調べる必要が出た。だが手元にその記録は無く、node_modules の更新時刻から推定するしかなかった。推定ではなく事実で答えられる状態を作るのが、このツールの出発点。
| 要素 | 役割 | 備考 |
|---|---|---|
| 即時記録 | 取り込んだその場で台帳に 1 行足す | 理由(なぜ入れたか)が残るのはこの経路だけ |
| スナップショット差分 | 各パッケージ管理の現状を台帳と突き合わせ、差分を追記 | 手で入れた分を後から拾う。理由は残らない |
| 取り込み台帳 | append-only の CSV。これが唯一の正典 | 人が grep でき、差分がそのまま履歴になる |
| osv-scanner | 脆弱性・悪意あるパッケージの照合 | 外部ツール。intakelog は再実装しない |
| レポート | 台帳と照合結果を 1 枚の HTML に合成 | 依存なし・self-contained |
即時記録だけでは、人が手で入れた分がまるごと落ちる。しかも落ちたことに気づけないので、「台帳がある」と信じてしまうぶん、台帳が無い状態より危険になる。だからスナップショット差分を必ず併走させて、抜けを構造的に埋める。逆にスナップショットだけでは「なぜ入れたか」が永久に残らないので、両方要る。
前提: osv-scanner が PATH に必要(レポートの照合で使う)。見つからない場合はインストール方法を案内して止まる。無い状態で「検出ゼロ」を返すことはしない。
npx intakelog scan — 何もインストールせずに、手元の状態を 1 回読むだけ。書き込みは行わない。
npm i -g intakelog — 繰り返し使うツールなので、常用はグローバル導入を推奨。
intakelog init — 台帳ファイルの置き場を決め、現在の状態を「初回スナップショット」として書き込む。intakelog add <name> --why "理由" で明示的に、または intakelog sync で差分をまとめて。intakelog report — osv-scanner を呼んで照合し、単一 HTML を出力してパスを表示する。
intakelog since 2026-08-04T09:00Z — 指定時刻以降に取り込んだものだけを一覧する。ここが本番。
$ intakelog report
==> 台帳: 132 行(最終更新 2026-08-05 19:46)
==> 照合: osv-scanner 2.4.0 / オフライン DB(外部送信なし)
lockfile 58 本 ... 48 本を走査
!! 走査できなかった: 10 本 — この範囲は未検査(異常なしではない)
./services/api/go.sum 理由: Go は go.mod を渡すこと
...
悪意あるパッケージ (MAL) : 0
CRITICAL : 2
未検査の lockfile : 10
→ ./intakelog-report.html
この出力で一番大事なのは「走査できなかった 10 本」の行。ここを黙って捨てると、出力は「異常なし」に見えてしまう。実際、試作段階でこの取りこぼしを 3 回踏んだ(エコシステムごとの DB 未取得・Go のファイル名の取り違え・引数の渡し方の誤り)。いずれも「0 件」と「未検査」が画面上で見分けられない形で出ていた。
date,kind,name,version,source,integrity,project,why,actor
| 列 | 中身 | 取れないとき |
|---|---|---|
date | 取り込んだ日時(タイムゾーン付き) | 空にする。推測で埋めない |
kind | 経路(npm / scoop / winget / pip / cargo / go / git / shell …) | — |
name / version | 名前と版。git は短いコミット ID | — |
source | 実 URL(レジストリ名だけで済ませない) | 空 |
integrity | ハッシュ・コミット ID | 空 |
project | 入れた先。グローバルなら空 | 空 |
why | 導入理由 1 行 | 差分検出のときは自動文言 |
actor | 人か、どのエージェントか | — |
形式を CSV にしたのは、人が grep でき、git の差分がそのまま履歴として読めるから。データベースを持たない。
照合は osv-scanner に委譲する。セキュリティツールの偽陰性は「異常なし」という誤った確信を作るので、無いより悪い。その責任は上流の専門ツールに置く。
未検査・取得失敗は必ず件数を出す。黙って捨てると出力が「異常なし」に化ける。試作で 3 回踏んだ失敗の共通点がこれ。
既存行を書き換えない・並べ替えない。訂正は新しい行を足して理由を書く。履歴が書き換わらないことが台帳の価値。
取れない値は空にする。推定値を事実として記録するのが、このツールで最も害の大きい振る舞い。
サプライチェーンを見る道具が、自分のサプライチェーンを抱えない。TypeScript の標準ライブラリだけで書く。
照合はローカル DB で行う。非公開プロジェクトの依存構成を外部の API に送らない。オンライン照会は明示指定したときだけ。
| 状態 | 内容 |
|---|---|
| 完了 | 名前の調査(商標・レジストリ・ドメイン)と npm 名の予約 |
| 完了 | 公開リポジトリの作成、ライセンス、秘匿情報スキャンの配線 |
| 次 | 台帳フォーマットの確定と、収集部(各パッケージ管理の読み取り)の実装 |
| 未着手 | レポート生成、CI、クロスプラットフォーム検証、初回リリース |
この構成のレビューで、次の 3 点が確定した。ここが実装の前提になる。