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中。

Go版本管理--go.sum的更多相关文章

  1. LeetCode - Two Sum

    Two Sum 題目連結 官網題目說明: 解法: 從給定的一組值內找出第一組兩數相加剛好等於給定的目標值,暴力解很簡單(只會這樣= =),兩個迴圈,只要找到相加的值就跳出. /// <summa ...

  2. Leetcode 笔记 113 - Path Sum II

    题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...

  3. Leetcode 笔记 112 - Path Sum

    题目链接:Path Sum | LeetCode OJ Given a binary tree and a sum, determine if the tree has a root-to-leaf ...

  4. POJ 2739. Sum of Consecutive Prime Numbers

    Sum of Consecutive Prime Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20050 ...

  5. BZOJ 3944 Sum

    题目链接:Sum 嗯--不要在意--我发这篇博客只是为了保存一下杜教筛的板子的-- 你说你不会杜教筛?有一篇博客写的很好,看完应该就会了-- 这道题就是杜教筛板子题,也没什么好讲的-- 下面贴代码(不 ...

  6. [LeetCode] Path Sum III 二叉树的路径和之三

    You are given a binary tree in which each node contains an integer value. Find the number of paths t ...

  7. [LeetCode] Partition Equal Subset Sum 相同子集和分割

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  8. [LeetCode] Split Array Largest Sum 分割数组的最大值

    Given an array which consists of non-negative integers and an integer m, you can split the array int ...

  9. [LeetCode] Sum of Left Leaves 左子叶之和

    Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are two l ...

随机推荐

  1. Requests方法 -- 参数关联

    一.删除草稿箱1.参数这篇https://www.cnblogs.com/Teachertao/p/11144726.html 2.删除刚才保存的草稿 3.用 fiddler 抓包,抓到删除帖子的请求 ...

  2. ifix与4G DTU对接实现数据显示

    前言: 因公司项目需求,需要使用4G DTU设备对远端RS 485设备进行数据采集,购买了相关产品进行技术实验,成功对接ifix将数据采集并显示,将过程记录,供大家参考. 1,4G DTU基本原理和配 ...

  3. 实现html页面转pdf

    实现方式比较简单,使用js代码实现的. 需要引入的js: 1.jQuery.js: 2.html2canvas.js(实现方式是先将Html页面转换成image图片然后在转换为pdf,所以转换之后会有 ...

  4. 总结开发中基于DevExpress的Winform界面效果

    DevExpress是一家全球知名的控件开发公司, DevExpress 也特指此公司出品的控件集合或某系列控件或其中某控件.我们应用最为广泛的是基于Winform的DevExpress控件组,本篇随 ...

  5. 如何开启MySQL远程连接

    MySql-Server 出于安全方面考虑只允许本机(localhost, 127.0.0.1)来连接访问,这对于 Web-Server 与 MySql-Server 都在同一台服务器上的网站架构来说 ...

  6. 浅析php环境配置

    PHP作为开源的服务器端脚本语言,在web应用方面非常广泛.如果你想下载某些开源应用,github上php开源软件选择往往比Java还多.最近,研究了linux下php的安装,主要有以下体会. PHP ...

  7. Feign实战技巧篇

    介绍Feign在项目中的正确打开方式 看了上一期Feign远程调用的小伙伴可能会问:阿鉴,你不是说上一期讲的是Feign的99%常用方式吗?怎么今天还有正确打开方式一说呀? 阿鉴:是99%的常用方式, ...

  8. JavaEE在线就业班2.0-(1)-《博学谷》

    JavaEE在线就业班2.0学习笔记 1. Java概述 1.1 Java语言背景介绍(了解) 语言:人与人交流沟通的表达方式计算机语言:人与计算机之间进行信息交流沟通的一种特殊语言Java语言是美国 ...

  9. Java基础(一):I/O多路复用模型及Linux中的应用

    IO多路复用模型广泛的应用于各种高并发的中间件中,那么区别于其他模式他的优势是什么.其核心设计思想又是什么.其在Linux中是如何实现的? I/O模型 I/O模型主要有以下五种: 同步阻塞I/O:I/ ...

  10. WPF上传图片到服务器文件夹

    1.前端用ListBox加载显示多张图片 1 <ListBox Name="lbHeadImages" Grid.Row="1" ScrollViewer ...