Go版本管理--go.sum


1. 簡介

為了確保一致性構建,Go引入了go.mod文件來標記每個依賴包的版本,在構建過程中go命令會下載go.mod中的依賴包,下載的依賴包會緩存在本地,以便下次構建。

考慮到下載的依賴包有可能是被黑客惡意篡改的,以及緩存在本地的依賴包也有被篡改的可能,單單一個go.mod文件並不能保證一致性構建。

為了解決Go module的這一安全隱患,Go開發團隊在引入go.mod的同時也引入了go.sum文件,用於記錄每個依賴包的哈希值,在構建時,如果本地的依賴包hash值與go.sum文件中記錄得不一致,則會拒絕構建。

本節暫不對模塊校驗細節展開介紹,只從日常應用層面介紹:

  • go.sum 文件記錄含義
  • go.sum文件內容是如何生成的
  • go.sum是如何保證一致性構建的

2. go.sum文件記錄

go.sum文件中每行記錄由module 名, 版本和哈希組成,並由空格分開,格式如下

<module> <version>[/go.mod] <hash>

比如某個go.sum文件記錄中記錄了github.com/google/uuid這個依賴的v.1.1版本的哈希值:

github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=  
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

Go module機制下,我們需要同時使用依賴包的名稱和版本才可以准確的描述一個依賴,為了方便敘述,下面我們使用依賴包版本來指代依賴包名稱和版本。

正常情況下,每個依賴包版本會包含兩條記錄:

  • 第一條記錄為該依賴包版本整體(所有文件)的哈希值,
  • 第二條記錄僅表示該依賴包版本中go.mod文件的哈希值

如果該依賴包版本沒有go.mod文件,則只有第一條記錄。如上面的例子中,v1.1.1表示該依賴包版本整體,而v1.1.1/go.mod表示該依賴包版本中go.mod文件。

依賴包版本中任何一個文件(包括go.mod)改動,都會改變其整體哈希值,此處再 **額 外記錄依賴包版本 **的go.mod文件主要用於計算依賴樹時不必下載完整的依賴包版本,只根據go.mod即可計算依賴樹。

每條記錄中的哈希值前均有一個表示哈希算法的h1:,表示后面的哈希值是由算法SHA-256計算出來的,自Go module從v1.11版本初次實驗性引入,直至v1.14 ,只有這一個算法。

go.sum文件中記錄的依賴包版本數量往往比go.mod文件中要多,這是因為二者記錄的粒度不同導致的。

go.mod只需要記錄直接依賴的依賴包版本,只在依賴包版本不包含go.mod文件時候才會記錄間接依賴包版本

go.sum則是要記錄構建用到的所有依賴包版本。

3. 生成

假設我們在開發某個項目,當我們在GOMODULE模式下引入一個新的依賴時,通常會使用go get命令獲取該依賴,比如:

require (
    github.com/google/uuid v1.0.0
)

go.sum文件中則會記錄依賴包的哈希值(同時還有依賴包中go.mod的哈希值),如:

github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

值得一提的是,在更新go.sum之前,為了確保下載的依賴包是真實可靠的,go命令在下載完依賴包后還會查詢GOSUMDB環境變量所指示的服務器,以得到一個權威的依賴包版本哈希值。如果go命令計算出的依賴包版本哈希值與GOSUMDB服務器給出的哈希值不一致,go命令將拒絕向下執行,也不會更新go.sum文件。

go.sum存在的意義在於,我們希望別人或者在別的環境中構建當前項目時所使用依賴包跟go.sum中記錄的是完全一致的,從而達到一致構建的目的。

4.校驗

假設我們拿到某項目的源代碼並嘗試在本地構建,go命令會從本地緩存中查找所有go.mod中記錄的依賴包,並計算本地依賴包的哈希值,然后與go.sum中的記錄進行對比,即檢測本地緩存中使用的依賴包版本是否滿足項目go.sum文件的期望。

如果校驗失敗,說明本地緩存目錄中依賴包版本的哈希值和項目中go.sum中記錄的哈希值不一致,go命令將拒絕構建。
這就是go.sum存在的意義,即如果不使用我期望的版本,就不能構建。

當校驗失敗時,有必要確認到底是本地緩存錯了,還是go.sum記錄錯了。
需要說明的是,二者都可能出錯,本地緩存目錄中的依賴包版本有可能被有意或無意地修改過,項目中go.sum中記錄的哈希值也可能被篡改過。

當校驗失敗時,go命令傾向於相信go.sum,因為一個新的依賴包版本在被添加到go.sum前是經過GOSUMDB(校驗和數據庫)驗證過的。此時即便系統中配置了GOSUMDB(校驗和數據庫),go命令也不會查詢該數據庫。

5.校驗和數據庫

環境變量GOSUMDB標識一個checksum database,即校驗和數據庫,實際上是一個web服務器,該服務器提供查詢依賴包版本哈希值的服務。

該數據庫中記錄了很多依賴包版本的哈希值,比如Google官方的sum.golang.org則記錄了所有的可公開獲得的依賴包版本。

除了使用官方的數據庫,還可以指定自行搭建的數據庫,甚至干脆禁用它(export GOSUMDB=off)。

如果系統配置了GOSUMDB,在依賴包版本被寫入go.sum之前會向該數據庫查詢該依賴包版本的哈希值進行二次校驗,校驗無誤后再寫入go.sum

如果系統禁用了GOSUMDB,在依賴包版本被寫入go.sum之前則不會進行二次校驗,go命令會相信所有下載到的依賴包,並把其哈希值記錄到go.sum中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM