概要
pnpm installするたびに出る「Ignored build scripts」の警告。これはstrictDepBuilds=trueというセキュリティ設定によるもので、サプライチェーン攻撃対策として重要なのだが、出る警告を一つずつ手動で確認するのは面倒。AIに各パッケージのスクリプト内容を読ませて安全性を評価させ、allowBuilds / ignoredBuilds / 未分類の3分類で管理するようにした話。そして、そういう知見をClaude Codeのスキルとして保存して再利用可能にするワークフローについてのまとめ。
この警告は何か
pnpm 10.xで.npmrcにstrictDepBuilds=trueを設定すると、依存パッケージのlifecycle scripts(postinstall等)がデフォルトでブロックされる。ブロックされたパッケージがあると、pnpm installのたびにこういう警告が出る。
╭ Warning ───────────────────────────────────────────────────────╮
│ │
│ Ignored build scripts: @parcel/watcher@2.5.4, │
│ core-js-pure@3.48.0, core-js@3.48.0, │
│ svelte-preprocess@6.0.3. │
│ Run "pnpm approve-builds" to pick which dependencies │
│ should be allowed to run scripts. │
│ │
╰────────────────────────────────────────────────────────────────╯なぜこの設定が必要かというと、npmパッケージのpostinstallスクリプトは、パッケージのインストール時に自動実行される。つまり、悪意のあるコードがpostinstallに仕込まれていた場合、npm installしただけで実行されてしまう。実際に過去にこういう事件が起きている。
- event-stream事件 — 人気パッケージのメンテナンス権限を譲り受けた第三者が、暗号通貨ウォレットを狙う悪意あるコードをpostinstallに仕込んだ
- ua-parser-js事件 — npmアカウントが乗っ取られ、暗号通貨マイナーをpostinstallで実行するバージョンが公開された
strictDepBuilds=trueはこういうサプライチェーン攻撃を防ぐための設定で、デフォルトですべてのlifecycle scriptsをブロックする。
pnpm approve-buildsで全部許可はNG
警告には「Run pnpm approve-builds to pick which dependencies should be allowed to run scripts.」と書いてある。これを実行すると対話的にパッケージを選んで許可できるのだが、面倒だからと全部許可してしまうとセキュリティ設定の意味がなくなる。各パッケージのスクリプトが何をしているか、個別に評価して判断する必要がある。
でも手動確認は面倒
各パッケージのpostinstallが何をしているか確認するには、node_modulesの中を読まないといけない。例えばこういうコマンドで確認できる。
# パッケージのscriptsフィールドを確認
node -e "const p = require('./node_modules/@parcel/watcher/package.json'); console.log(JSON.stringify(p.scripts, null, 2))"
# 実際のスクリプトコードを読む
cat node_modules/@parcel/watcher/scripts/build-from-source.js
# プリビルトバイナリの存在確認
ls node_modules/@parcel/watcher-*パッケージが4つぐらいならまだしも、プロジェクトが大きくなると確認対象が増えてくる。この作業を毎回手動でやるのは現実的ではない。
AIに評価させる
ということでClaude Codeの出番。Claude Codeに「このパッケージのpostinstallスクリプトの内容を読んで、何をしているか評価して」と頼むと、node_modulesの中を読んでスクリプトの内容を分析してくれる。
自分がやったのは、警告に出ているパッケージ名をそのままClaude Codeに渡して、それぞれのスクリプトを読んでもらうという流れ。
3分類で管理する
評価の結果を以下の3つに分類する。
- allowBuilds — スクリプトの実行を許可するもの。ネイティブバインディングのビルドなど、実行しないと動かないもの
- ignoredBuilds — スクリプトの実行が不要と判断したもの。プリビルトバイナリがあるケースや、単なるメッセージ表示など
- 未分類 — まだ評価していないもの。警告が出るままにしておく
ポイントは、未分類を「警告が出るまま」にしておくこと。不明なものは許可しない。新しいパッケージが追加されたときも、まず警告が出て、そこで評価するというフローになる。
実際の評価結果
今回評価したパッケージと、その結果は以下の通り。
| パッケージ | スクリプト | 内容 | 判定 |
|---|---|---|---|
| core-js | postinstall | Donationバナー表示のみ | allowBuilds |
| core-js-pure | postinstall | 同上 | allowBuilds |
| @parcel/watcher | install | 条件付きビルド。プリビルトバイナリあり | ignoredBuilds |
| svelte-preprocess | postinstall | echoで案内メッセージ表示 | ignoredBuilds |
core-jsのpostinstallは、ターミナルにdonation(寄付のお願い)バナーを表示するだけ。悪意のあるコードは含まれていないので、allowBuildsに入れる。実行しなくても動作に影響はないが、メンテナーへのリスペクトとしてallowBuildsにした。
@parcel/watcherのinstallスクリプトは、プリビルトバイナリがない環境でソースからビルドするためのもの。普通の環境ではプラットフォーム固有のプリビルトバイナリ(@parcel/watcher-darwin-arm64等)がすでにインストールされるので、このスクリプトを実行する必要がない。ignoredBuildsに入れる。
svelte-preprocessのpostinstallは、echoコマンドで「svelte-preprocessはSvelte 4以降不要です」みたいな案内メッセージを表示するだけ。ignoredBuildsに入れる。
.npmrcにコメント付きで記録する
評価結果は.npmrcにコメント付きで書いておく。なぜその判定にしたかを記録しておかないと、後から見たときに「なんでこれ許可したんだっけ」となる。
# セキュリティ設定
strictDepBuilds=true
# allowBuilds: スクリプト実行が必要なパッケージ
# - core-js / core-js-pure: postinstallでdonationバナー表示(無害)
# - unrs-resolver: ネイティブバインディングのビルド(必須)
allowBuilds[]=core-js
allowBuilds[]=core-js-pure
allowBuilds[]=unrs-resolver
# ignoredBuilds: スクリプト実行が不要と判断したパッケージ
# - @parcel/watcher: プリビルトバイナリで動作。install scriptは手動ビルド時のみ
# - svelte-preprocess: postinstallはechoで案内メッセージを表示するだけ
ignoredBuilds[]=@parcel/watcher
ignoredBuilds[]=svelte-preprocessignoredBuildsに入れたパッケージは、スクリプトが実行されないのでinstall時間が短くなるという副次効果もある。
判断基準のまとめ
自分が使った判断基準はだいたい以下の通り。
- ネイティブバインディングのビルド → allowBuilds(実行しないと動かない)
- バナー・メッセージ表示のみ → allowBuilds or ignoredBuilds(無害なので好みで)
- プリビルトバイナリがある場合のビルドスクリプト → ignoredBuilds(実行不要)
- 内容がよくわからないスクリプト → 未分類のまま(警告を残して後で調べる)
Claude Codeのスキルにする
ここからが後半の話。
上で書いたような「パッケージのスクリプトを評価して分類する」というワークフロー、これをClaude Codeのスキルとして保存しておくと、次回以降同じ作業をAIが再現してくれる。
Claude Codeのスキルというのは、Claude Codeに特定のタスクをやらせるための手順書みたいなもの。自分の場合、ブログ記事やメモ、あるいはネットで見つけた情報をコピペしてClaude Codeに「これスキルにして」と渡すだけで、Claude Codeがそれを再利用可能な形にまとめてくれる。
この記事の内容もそのままスキルの素材になる。例えば以下のような情報を渡す。
strictDepBuilds=trueの意味- allowBuilds / ignoredBuilds / 未分類の3分類
- 各パッケージの評価に使うコマンド
- 判断基準
これをスキルにしておけば、新しいプロジェクトで同じ警告が出たときに「pnpmのbuild scripts評価して」とClaude Codeに言うだけで、同じワークフローを再現してくれる。
スキル化のコツ
自分がやっているのは、「これまた使いそうだな」と思った情報に出くわしたら、その場でClaude Codeに「スキルにして」と言うこと。素材は何でもいい。
- 自分がやった作業の手順
- 誰かのブログ記事
- 公式ドキュメントの一部
- Xで見かけたTips
「役に立ちそう」と思った情報をコピペしてスキルにするだけ。自分で手順を整理する必要もない。Claude Codeが勝手にまとめてくれる。
ポイントは、スキルにする素材は完璧である必要がないということ。雑なメモでも、スクリーンショットの説明でも、何でもいい。Claude Codeがコンテキストを理解して、次回使えるような形にしてくれる。これがClaude Codeの使いこなしのコツの一つかなと自分は考えている。
余談
strictDepBuildsの設定は、チーム開発では特に重要。一人で開発していると「まぁ大丈夫だろう」で済ませがちだが、チームで.npmrcを共有していれば、誰かが新しいパッケージを追加したときに自動的に警告が出る。そこで評価して分類するというフローが自然にできる。
この評価結果をコメント付きで.npmrcに残しておけば、チームの誰が見ても「なぜこのパッケージのスクリプト実行を許可/不許可にしたか」がわかる。セキュリティの判断をコードに残すという意味でも良い習慣だと思う。