2026 年每日通報的 CVE 數量比前一年多 131%。

相依套件

什麼是鎖定檔(lockfile)?

鎖定檔記錄套件管理工具所解析出的每個相依套件的確切版本,包括直接與遞移相依套件,讓下一次安裝能得到相同的相依樹。它是您對建置所能擁有的最佳計畫,但並不是建置實際使用了什麼的紀錄。

更新日期

鎖定檔記錄了什麼

您的 manifest,例如 package.json 或 pyproject.toml,列出您所相依的套件以及您接受的版本範圍。套件管理工具會將這些範圍轉換成整個相依樹的確切版本,包括遞移相依套件,並將結果寫入鎖定檔。 npm 的文件將 package-lock.json 描述為記錄「所產生的確切相依樹,讓後續的安裝能產生完全相同的相依樹」。

package-lock.json 中的單一項目如下所示:

"node_modules/raw-body": {
  "version": "3.0.0",
  "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
  "integrity": "sha512-...",
  "dependencies": {
    "bytes": "3.1.2",
    "http-errors": "2.0.0",
    "iconv-lite": "0.6.3",
    "unpipe": "1.0.0"
  }
}
  • version 是所選定的確切版本。
  • resolved 是它的擷取來源:registry 的 tarball URL,或是附帶 commit 的 git URL。
  • integrity 是該 tarball 的子資源完整性(Subresource Integrity)雜湊值,因此遭竄改的下載內容會驗證失敗。
  • dependencies 是它自己的相依套件,相依樹(也就是相依關係圖)就是這樣串接起來的。

各套件管理工具的鎖定檔

套件管理工具 鎖定檔 安裝但不變更鎖定檔
npmpackage-lock.jsonnpm ci
Yarn (Berry)yarn.lockyarn install --immutable
pnpmpnpm-lock.yamlpnpm install --frozen-lockfile
uvuv.lockuv sync --locked
Poetrypoetry.lockpoetry install
CargoCargo.lockcargo build --locked
BundlerGemfile.lockbundle config set frozen true
Go modules go.mod 的版本與 go.sum 的校驗和 建置指令預設不會更新 go.mod

若只使用 pip,常見的替代做法是列出確切版本的 requirements.txt。它會固定所列出的套件,但未列出的套件在每次安裝時都會重新解析。

在 CI 中使用凍結安裝

鎖定檔只有在建置依據它安裝時才有用。一般的 npm install 在 package-lock.json 與 package.json 不再一致時可能會更新鎖定檔,讓建置悄悄解析出新的相依樹。npm ci 則是專為自動化環境設計:

  • 它要求必須有 package-lock.json 或 npm-shrinkwrap.json。
  • 若鎖定檔與 package.json 不一致,它會以錯誤結束,而不是更新鎖定檔。
  • 它會先移除既有的 node_modules。
  • 它絕不會寫入 package.json 或鎖定檔。

上表中的其他指令,也為各自的套件管理工具執行相同的工作。

應用程式與函式庫

應用程式以及任何您要部署的軟體,都應該 commit 鎖定檔。對函式庫而言,鎖定檔只會鎖定您自己的開發與 CI 環境:npm 從不發布 package-lock.json,而且除了根專案之外一律忽略它。安裝您函式庫的應用程式會在您的版本範圍內自行解析其相依套件。npm 唯一的例外是 npm-shrinkwrap.json,它會隨套件發布並具有優先權,但大多數函式庫都不應該使用它。

為何鎖定檔不是出貨內容的紀錄

鎖定檔是單一專案中單一套件管理工具的計畫。產出您發布版本的建置,做的事情不只是依循這份計畫:

  • 建置可能根本沒有使用它。非凍結安裝、缺少鎖定檔,或 monorepo 中的第二份鎖定檔,都代表相依樹的解析方式與您正在查看的檔案不同。
  • 快取。從 CI 快取還原的套件不經擷取就直接安裝,而以部分鍵值還原的快取可能早於目前的鎖定檔。請參閱 GitHub Actions 快取隱藏了什麼。
  • 建置工具。setup action、編譯器、linter 與程式碼產生器透過其他管道進入建置,並帶有各自的相依樹。
  • 下載與安裝腳本。建置步驟中的 curl 或套件的安裝腳本,會擷取任何鎖定檔都沒有列出的程式碼,也就是隱藏相依性。
  • 基礎映像檔。容器建置會拉取映像檔與作業系統套件,而這些都不在任何程式語言的鎖定檔之內。

完整性雜湊值對上述情況都沒有幫助。它們證明鎖定檔中的套件未遭竄改,卻無法說明建置在鎖定檔之外擷取了什麼。將鎖定檔轉換成 SBOM 的 SCA 工具也承襲了同樣的盲點。

記錄建置,保留鎖定檔

請持續 commit 鎖定檔,並以凍結安裝依據它們安裝。它們能讓建置可重複執行,但光靠鎖定檔並不能構成可重現建置。至於發布版本包含什麼的紀錄,CRACI 記錄的是建置本身:其 GitHub Actions 執行器上能辨識套件的代理伺服器,會記錄每個作業擷取的每個套件,包括從 CI 快取還原的套件,而每個作業的 SBOM 都會標示自身的完整性。比起掃描鎖定檔,這份紀錄能更完整地呈現實際使用中的相依套件。請參閱建置時 SBOM,或預約示範,在您自己的一次建置上比較兩者。

鎖定檔:常見問題

什麼是鎖定檔?

鎖定檔是套件管理工具寫入的檔案,記錄它所解析出的每個相依套件(包括直接與遞移相依套件)的確切版本,以及其來源與校驗和。之後的安裝會讀取它來重現相同的相依樹,而不是重新解析版本範圍。

我應該 commit 鎖定檔嗎?

應該,適用於應用程式以及任何您要部署的軟體。若未 commit 鎖定檔,每次全新安裝都會重新解析版本範圍,並可能引入新的遞移相依套件版本。請 commit 鎖定檔,並在 CI 中以 npm ci 等凍結安裝依據它安裝。

鎖定檔會固定遞移相依套件嗎?

會,這正是它的主要工作。manifest 只列出您的直接相依套件及其允許的版本範圍;鎖定檔則記錄相依樹中每個套件所選定的確切版本。

鎖定檔適用於我發布的函式庫嗎?

對您的使用者而言並不適用。以 npm 為例,它從不發布 package-lock.json,而且除了根專案之外一律忽略它。安裝您函式庫的應用程式,會在您的 package.json 允許的範圍內自行解析其相依套件。

package-lock.json 中的 integrity 欄位有什麼作用?

它保存套件 tarball 的子資源完整性(Subresource Integrity)雜湊值,通常是 sha512。npm 會以它檢查下載的套件,因此已鎖定版本的 tarball 若遭竄改就會安裝失敗。它保護的是鎖定檔中的套件,而不是建置在鎖定檔之外擷取的任何內容。

鎖定檔和 SBOM 一樣嗎?

不一樣。鎖定檔是一項輸入:套件管理工具在單一專案中依循的計畫。SBOM 則是一個發布版本的清冊。SCA 工具常將鎖定檔轉換成 SBOM,前提是建置完全依照鎖定檔安裝,而且沒有安裝其他任何東西。

比較您的鎖定檔與您的建置

在 CRACI 上執行一個工作流程,將它記錄下來的已擷取套件 SBOM,與您的鎖定檔內容並列比較。

預約示範