この記事のポイント
- 公開から 7 日たっていないバージョンは入れない(
minimumReleaseAge) package.jsonのバージョンは^を付けずに固定し、CI は lockfile のとおりに入れる- 更新は Dependabot の PR で受け取り、こちらも公開から 7 日待つ(
cooldown) - pnpm のバージョンも
packageManagerで固定する
何に備えるのか
npm のパッケージは、作者のアカウントが乗っ取られると、悪いコードを入れたバージョンが公開されることがあります。よく使われるパッケージでも起きていて、インストールしただけで、手元や CI の認証情報(npm や GitHub のトークン、クラウドの鍵など)を盗まれます。
こうしたバージョンは、多くの場合、公開から数時間〜数日で見つかって消されます。危ないのは、公開されてすぐのバージョンを、知らないうちに入れてしまうことです。
次のようなときに起きます。
^1.2.0のような範囲指定で、pnpm installやpnpm updateが新しいバージョンを選ぶ- 依存パッケージの依存パッケージ(間接的な依存)が、新しいバージョンに変わる
- CI が lockfile と違うバージョンを入れる
ここで紹介する設定は、どれも「新しいバージョンは、少し待ってから、目に見える形で入れる」ためのものです。
公開から 7 日たっていないバージョンを入れない
pnpm 10.16 から、minimumReleaseAge で、公開から指定した時間(分)がたっていないバージョンを選ばないようにできます。間接的な依存にも効きます。
# pnpm-workspace.yaml
minimumReleaseAge: 10080 # 7 日ワークスペースを使っていなくても、pnpm の設定は pnpm-workspace.yaml に書きます。
セキュリティの修正などで、新しいバージョンをすぐに入れたいときは、パッケージ名を一時的に除外します。
minimumReleaseAgeExclude:
- some-packageこの確認は、バージョンを選ぶとき(lockfile を作る・更新するとき)にだけ行われます。lockfile にあるバージョンをそのまま入れるときは確かめないので、設定を入れる前の lockfile に新しいバージョンがあっても、そのまま残ります。
バージョンを固定する
saveExact を有効にすると、pnpm add や pnpm update で、package.json に ^ を付けずにバージョンを書きます。
# pnpm-workspace.yaml
saveExact: true{
"dependencies": {
"astro": "7.4.2"
}
}実際に入るバージョンは lockfile で決まりますが、package.json も固定しておくと、入っているバージョンがひと目でわかり、更新は必ず package.json の差分として残ります。
CI では、lockfile と違うものを入れないように、--frozen-lockfile を付けます。lockfile が package.json と合っていなければ、インストールが失敗します。
- run: pnpm install --frozen-lockfile更新は Dependabot の PR で受け取る
バージョンを固定すると、自分で更新しない限り古いままになります。Dependabot に、週 1 回、更新の PR を作ってもらいます。
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
groups:
minor-and-patch:
update-types:
- minor
- patchcooldownで、公開から 7 日たったバージョンだけを PR にします。minimumReleaseAgeと日数を合わせておかないと、PR の CI でインストールが失敗します- 脆弱性の修正(セキュリティアップデート)には、
cooldownは効きません。すぐに PR が作られます - マイナーとパッチは 1 つの PR にまとめ、メジャーはパッケージごとの PR にします
PR になるので、どのパッケージがどう変わったかを確認でき、CI が通ってから取り込めます。
pnpm と GitHub Actions も固定する
pnpm 自体のバージョンは、package.json の packageManager で固定します。
{
"packageManager": "pnpm@10.33.4"
}pnpm/action-setup は、version を指定しなければ、この値を読みます。手元と CI で同じ pnpm を使えます。
GitHub Actions のアクションも、タグではなくコミットの SHA で指定します。タグは付け替えられるので、アクションが乗っ取られると、同じタグのまま中身が変わることがあります。
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0Dependabot に package-ecosystem: github-actions を追加すると、SHA の更新も PR にしてくれます。
これで防げないこと
- 7 日たっても見つからない、悪いバージョン
- 以前から入っているパッケージに、もともと含まれている問題
7 日待つのは、多くの人が使って問題が見つかるのを待つ、という考え方です。更新の PR を取り込むときは、変わったパッケージの名前と、大きな変更がないかを見ておきます。
なお pnpm 10 では、依存パッケージの postinstall などのスクリプトは、許可したものしか実行されません。インストールしただけで悪いコードが動く経路を、既定で減らしています。