Edited at

yarn upgrade で更新できない間接的な依存パッケージだけをアップグレードするには


TL; DR:

yarn.lock から当該のパッケージのセクションを削除して yarn install すればアップグレードできる。


困ったこと

GitHub にソースコードをホストしているとある npm パッケージにおいて、 GitHub の Security Alerts が fstream < 1.0.12 の脆弱性を報告した。

スクリーンショット 2019-06-03 11.25.13.png

yarn upgrade fstream で最新バージョンにアップグレードしようとしたが……

$ cd my_npm_pkg

$ yarn upgrade fstream
yarn upgrade v1.16.0
[1/5] 🔍 Validating package.json...
[2/5] 🔍 Resolving packages...
[3/5] 🚚 Fetching packages...
[4/5] 🔗 Linking dependencies...
warning " > react-on-rails@8.0.3" has unmet peer dependency "babel-runtime@>= 6".
[5/5] 🔨 Rebuilding all packages...
success Saved lockfile.
success Saved 0 new dependencies.
✨ Done in 7.07s.

$ git diff
(出力なし)

実行しても yarn.lock が変化しない。これは、この npm パッケージが fstream に直接的に依存していないためだった。


調査

どのパッケージが fstream に依存しているかは yarn why fstream で分かる:

$ yarn why fstream

yarn why v1.16.0
[1/4] 🤔 Why do we have the module "fstream"...?
[2/4] 🚚 Initialising dependency graph...
[3/4] 🔍 Finding dependency...
[4/4] 🚡 Calculating file sizes...
=> Found "fstream@1.0.11"
info Reasons this module exists
- "node-sass#node-gyp" depends on it
- Hoisted from "node-sass#node-gyp#fstream"
- Hoisted from "node-sass#node-gyp#tar#fstream"
info Disk size without dependencies: "140KB"
info Disk size with unique dependencies: "416KB"
info Disk size with transitive dependencies: "788KB"
info Number of shared dependencies: 12
✨ Done in 0.70s.

元を辿れば、(この npm パッケージが直接的に依存している) node-sass が間接的に fstream を引き入れたようだ。


解決策


1. node-sass をインストールし直す

yarn remove node-sass && yarn add -D node-sass で node-sass をインストールし直せば今回は解決すると思われる。

ただ、こうすると node-sass が依存するパッケージがすべてアップグレードされてしまう。互換性のある semver の範囲内でアップグレードされるとはいえ、一応差分をチェックしないと安心できない。もし今後同様の状況になって、 fstream に依存するパッケージが複数に増えていたら、差分はさらに大きくなることが予想される。可能なら fstream だけアップグレードしたい。


2. yarn.lock から fstream を消して yarn install

yarn.lock から fstream を消して yarn install すればどうかと思い試してみた。

まずは yarn.lock から fstream で始まる行を探し、そのセクションを丸ごと削除する。

$ git diff

diff --git a/yarn.lock b/yarn.lock
index 3983d00b8b..9a3e1ef0cf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3624,15 +3624,6 @@ fsevents@^1.2.7:
nan "^2.9.2"
node-pre-gyp "^0.10.0"

-fstream@^1.0.0, fstream@^1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
- dependencies:
- graceful-fs "^4.1.2"
- inherits "~2.0.0"
- mkdirp ">=0.5 0"
- rimraf "2"
-
function-bind@^1.0.2, function-bind@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"

yarn install を実行し、 yarn.lock が更新されたか見てみる。

$ yarn install

(略)

$ git diff

diff --git a/yarn.lock b/yarn.lock
index 3983d00b8b..3a44640600 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3625,8 +3625,9 @@ fsevents@^1.2.7:
node-pre-gyp "^0.10.0"

fstream@^1.0.0, fstream@^1.0.2:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
+ integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"

fstream のセクションが復活し、最新バージョンにアップグレードされたことが分かる。


yarn.lock の一部を書き換えてもいいのか?

yarn の依存解決アルゴリズムを理解しているわけではないが、多分大丈夫だろう。 yarn.lock に書かれているべきパッケージが抜け落ちていれば、 yarn install は自動的にパッケージをインストールして yarn.lock に追記すると思われる。 package.json の dependencies に手でパッケージを書き加えてから yarn install するのと状況は同じなのだから。


備考:環境


  • node 10.16.0

  • npm 6.9.0

  • yarn 1.16.0 (yarn lockfile v1)