使用 PNPM 升級傳遞依賴關係:修復安全漏洞而不破壞項目
修復安全漏洞可能是一項令人沮喪的任務,特別是當涉及到傳遞依賴關係時。學習如何在不影響直接依賴的情況下升級它們。
如今,安全漏洞在軟件開發中是一個常見的問題。幸運的是,我們有像 GitHub Dependabot 這樣的工具來幫助我們保持依賴項的最新狀態,通過自動檢測和拉取請求。
然而,它並不總是如預期般運行。由於某些依賴關係是傳遞的,這些工具可能難以升級它們,因為它們不知道變更的影響以及在出現衝突時應該做出何種決定。這些情況需要我們手動處理。
不起作用的方法
- 官方命令如
pnpm up
會搞亂你的pnpm-lock.yaml
文件。在撰寫本文時,仍有 相關問題 開放。 - 安裝具有目標傳遞依賴關係的直接依賴的最新版本可能不起作用。如果直接依賴沒有升級版本定義,傳遞依賴關係將不會升級,因為它已在
pnpm-lock.yaml
文件中被解析和鎖定。
解決方案
在 PNPM 中,overrides
字段 是一個強大的功能,允許你覆蓋一些版本解析。 我們將使用此功能來升級傳遞依賴關係並使變更儘可能最小化。
讓我們以上述的 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
包在 pnpm-lock.yaml
中被升級到 1.15.6
,變更最小化。
現在你可以從 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,我們使用這種方法來保持我們的依賴項最新且安全。