使用 PNPM 升級傳遞依賴項:修復安全漏洞而不破壞其他功能
修復安全漏洞可能是一項令人十分煩惱的工作,尤其當涉及到傳遞依賴項時。學習如何在不影響直接依賴項的情況下進行升級。
當今,安全漏洞已成為軟體開發中的常見問題。幸運的是,我們有像 GitHub Dependabot 這樣的工具幫助我們通過自動檢測和拉取請求來保持依賴項的最新。
然而,它並不總是能如預期運作。由於某些依賴項是傳遞性的,升級這些依賴項可能對這些工具來說是一項困難的任務,因為它們不知道更改的影響以及發生衝突時應做什麼決策。我們需要手動處理這些情況。
不起作用的方法
- 像
pnpm up
這樣的官方命令會搞亂你的pnpm-lock.yaml
文件。在撰寫本文時,這個 問題 仍然存在。 - 安裝具有目標傳遞依賴項的最新版本直接依賴項可能無效。如果直接依賴項沒有升級版本定義,傳遞依賴項將不會被升級,因為它已在
pnpm-lock.yaml
文件中解析和鎖定。
解決方案
overrides
欄位 是 PNPM 中的一個強大功能,允許你覆蓋某些版本解析。我們將使用此功能來升級傳遞依賴項,並使更改儘可能最小化。
讓我們以上面的 Dependabot 警報為例。它告訴我們 follow-redirects
套件有一個安全漏洞,修補版本是 1.15.6
。然而,直接依賴項 gatsby
使用 axios
,而它依賴於 [email protected]
。
步驟 1:查找傳遞依賴項
有很多方法可以定位傳遞依賴項,但我會推薦最直接的方法:搜尋 pnpm-lock.yaml
文件。
那麼 "pnpm why" 呢?
pnpm why <package>
命令確實有用。然而,在這種情況下,它可能會讓你感到困惑。例如,當我運行 pnpm why follow-redirects
時,這是輸出的一部分:
實際上,在 pnpm-lock.yaml
文件中 follow-redirects
只有一個解析。pnpm why
命令可能會向你顯示依賴於該包同一版本的多條路徑。
步驟 2:添加覆蓋
最簡單的情況是,在 pnpm-lock.yaml
文件中只有一個解析。你可以直接將覆蓋添加到 package.json
文件:
如果你在一個工作區中,你應該將覆蓋添加到工作區的根 package.json
文件。
步驟 3:應用更改
運行 pnpm install
來應用更改。我們可以看到 follow-redirects
套件升級到了 1.15.6
,並且在 pnpm-lock.yaml
文件中僅有最小的更改。
現在你可以從 package.json
文件中移除 overrides
欄位以保持其整潔。然後再次運行 pnpm install
驗證沒有 overrides
欄位也能應用更改。
疑難排解
上述步驟是理想情況。事情可能並不總是如預期進行。 這裡有一些疑難排解的建議:
移除 "overrides" 欄位後版本被還原
這可能發生在依賴包有固定版本或一個不包括目標版本的範圍。檢查依賴包的 package.json
文件,在此情況下,即 axios
,看看是否適用。
如果適用,你需要將 overrides
欄位保留在 package.json
文件中,直到依賴包升級版本定義。
傳遞依賴項有多個解析
隨著專案的增長,pnpm-lock.yaml
文件可能會有多個相同套件的解析。例如,可能有同一套件 foo
的兩個主要版本:
漏洞報告顯示 [email protected]
有一個安全問題,已在 1.0.1
中修復,而 [email protected]
不受影響。我們不能簡單地添加 foo
的覆蓋:
- 如果我們添加覆蓋
"foo": "^1.0.1"
,[email protected]
將被降級到1.0.1
。這可能會破壞專案,因為[email protected]
可能有一些在依賴包中使用的新功能。 - 如果我們添加覆蓋
"foo": "^2.0.0"
,[email protected]
將被升級到2.0.0
。這可能會破壞專案,因為[email protected]
可能有一些重大更改。
假設 foo
遵循 語義版本控制,我們可以像這樣添加覆蓋:
這將只升級 [email protected]
到 1.0.1
,並保持 [email protected]
不變。
結論
在 PNPM 支援直接升級傳遞依賴項之前,overrides
欄位是解決安全漏洞而不破壞其他功能的一個不錯的變通方法。我希望本文能幫助你更有效地處理這些情況。在 Logto,我們使用這種方法來保持依賴項的最新和安全。