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

CI/CD

GitHub Actions 快取:運作方式與它所隱藏的內容

GitHub Actions 快取會在工作流程執行之間保存檔案,讓作業略過已經下載過的內容。它能加快建置。但這也代表套件不經下載就進入了您的建置,而多數建置記錄從來看不到這一點。

更新日期

快取如何運作

actions/cache 動作會在作業結束時,以某個 key 保存一組路徑,並在之後的作業開始時還原。典型的 npm 設定會快取套件管理工具的下載快取,並以 lockfile 作為 key:

- uses: actions/cache@v4
  with:
    path: ~/.npm
    key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
    restore-keys: |
      npm-${{ runner.os }}-
- run: npm ci

還原時,這個動作會先尋找與 key 完全相符的快取,接著是部分相符,再依序比對每個 restore-keys 前綴。當多個快取符合同一個前綴時,它會還原最近建立的那一個。這種退而求其次的機制,讓 lockfile 變更後建置依然快速,但也代表作業可能從為舊版 lockfile 建立的快取開始。

很多時候您根本不需要這個動作。setup-node、setup-python、setup-java、setup-go、setup-ruby 與 setup-dotnet 都內建快取功能。在 Node.js 方面,setup-node 快取的是 npm、Yarn 與 pnpm 的全域套件資料,而不是 node_modules;當 package.json 將 npm 宣告為其 packageManager 時,它會自動啟用 npm 快取。

範圍與限制

規則 GitHub 的做法
一次執行可以還原哪些快取 自身分支與預設分支的快取;pull request 也可還原其基底分支的快取
pull request 可以寫入什麼 只能寫入範圍限於其 merge ref 的快取,無法寫入預設分支
儲存空間 預設每個儲存庫 10 GB;組織與企業擁有者可以調高
淘汰機制 超過 7 天未存取的項目,以及儲存空間已滿時最久未使用的項目
機密 不要快取機密:任何擁有 pull request 權限的人都能讀取快取內容

快取對您的 SBOM 隱藏了什麼

快取是一條繞過套件庫的捷徑。這正是它的目的,也是它會讓每一種建置用量記錄都產生混淆的原因:

  • 沒有下載,就沒有痕跡。從快取還原的套件在安裝時不會向套件庫發出請求。以建置網路流量建立的記錄,除非追蹤快取,否則會漏掉這些套件。
  • 新 key 底下的舊內容。部分相符的 restore-keys 會還原為較早 lockfile 建立的快取。之後的安裝會新增或替換有變動的部分,但作業一開始所用的內容,並不是目前 lockfile 所描述的內容。
  • 不只是您的相依套件。快取也會存放建置工具、編譯器與產生的檔案,這些都不會列在任何應用程式 manifest 中。
  • 掃描無從分辨。以 lockfile 為基礎的 SBOM 描述的是 lockfile 寫了什麼,無論作業是否確實從快取安裝了完全相同的內容。

這與更大的問題有何關聯,請參閱為什麼 lockfile 不是已出貨內容的記錄與遞移相依套件。

快取汙染

同一個儲存庫中的工作流程會共用快取,這讓快取成為工作流程之間的一條通道。2024 年 5 月,資安研究人員 Adnan Khan 證實,任何能在預設分支脈絡中執行程式碼的人,無論是透過有漏洞的 pull_request_target 工作流程,還是遭入侵的相依套件,都能覆寫會還原快取的工作流程中的檔案。攻擊者只要取得執行中作業的快取權杖,就能塞滿儲存庫的快取,迫使 GitHub 淘汰合法項目,再以相同的 key 寫入遭汙染的項目。還原這些項目的版本發布工作流程,就會帶著自己的機密執行攻擊者的檔案。

降低風險的方法:

  • 從乾淨的狀態建置版本,或只使用由版本發布工作流程自己寫入的快取。
  • 絕不在預設分支脈絡中執行不受信任的 pull request 程式碼。
  • 不要讓機密與權杖出現在快取路徑中。
  • 將快取還原的內容視為建置的輸入,並以檢視下載內容的同等標準審視。

CRACI 如何處理快取

CRACI 是 GitHub Actions 執行器,因此 actions/cache 與 setup-* 快取會和現在一樣運作,容器層快取也是如此。快取也是 CRACI 執行建置速度約為 GitHub 託管執行器兩倍的原因之一,另外還有更快的硬體與更短的排隊時間。

改變的是記錄。CRACI 具備套件感知能力的代理伺服器會記錄作業取用的套件,而佐證資料會隨快取一起傳遞:當作業還原快取時,CRACI 會把它所知道的相依套件帶入該作業的 SBOM。

  • 每個快取都有完整性狀態。每個快取都和每個作業一樣有完整性狀態。還原了不完整快取的作業會得到不完整的 SBOM,而它產生的快取也會延續這個狀態,因此缺漏絕不會悄悄變成完整的記錄。
  • 不從封存檔推測。CRACI 不會讀取快取封存檔內的套件 manifest。它之所以知道快取裡有什麼,是因為它記錄了產生該快取的作業。
  • 每個產生快取的作業只產生一個快取,再搭配在產生快取的作業中設為 default: deny 的對外連線(egress)政策,就能讓這份佐證資料保持可靠。詳情請見快取與 SBOM 完整性指南。

記錄如何運作,請參閱建置時 SBOM;或預約示範,在 CRACI 上執行您使用快取的工作流程。

GitHub Actions 快取:常見問題

GitHub 會保留 Actions 快取多久?

GitHub 會移除超過 7 天未存取的快取項目。當儲存庫超過儲存空間上限(預設 10 GB)時,也會依最後存取時間由舊到新淘汰快取。

setup-node 會快取 node_modules 嗎?

不會。actions/setup-node 的 cache 輸入快取的是 npm、Yarn 或 pnpm 套件管理工具的全域套件資料,而不是 node_modules。安裝步驟仍會執行,但會從還原的快取讀取套件,而不是重新下載。

pull request 可以讀取 main 分支的快取嗎?

可以。工作流程執行可以還原自身分支與預設分支的快取,pull request 也可以還原其基底分支的快取。在 pull request 中建立的快取,範圍限於其 merge ref,因此無法寫入預設分支的範圍。

在版本發布工作流程中使用 Actions 快取安全嗎?

這是一種取捨。2024 年發表的研究指出,任何能在預設分支工作流程中執行程式碼的人,都能汙染其他工作流程(包括版本發布工作流程)會還原的快取。發布版本或持有部署機密的工作流程,從乾淨的狀態建置,或只使用自己寫入的快取,會比較安全。

還原的快取會改變我的 SBOM 嗎?

有可能。從快取還原的套件不經下載就被安裝,因此以網路流量建立的記錄,除非追蹤快取,否則會漏掉這些套件。而掃描 lockfile 也無法告訴您快取中是否確實是那些版本。

保留快取,也保有完整的 SBOM

在 CRACI 上執行您的工作流程:快取依然能加速建置,而快取帶入的相依套件會留在每個作業記錄的 SBOM 中。

預約示範