Go 依赖库使用情况检测思路

背景

最近工作中遇到了这样一个场景:某个依赖库(Go 语言)需要下线,需要在 N 多个代码仓库中检测该库的使用情况。如果检测的仓库没有依赖这个库,或者只是间接依赖而没有间接调用依赖库的函数,则仓库可视为安全,否则可能有安全风险。对于有安全风险的仓库,需要手工检查具体使用情况并判断是否需要去除依赖库,此过程需要一定的人力成本。

一种方法是用 go mod graph 命令来检查依赖库的情况,但由于有较多公共库依赖了这个库,导致 N 个待检测的代码仓库中的大部分都间接依赖了该库,因此用 go mod graph 不能进行有效的筛选。如果有一种方案能进一步缩小排查范围,则可以减少排查的成本。

思路

如果仓库间接调用了依赖库函数,那对应的 Package 会在 import path 的链路上。通过 import path 分析依赖可以比 go mod graph 的依赖进一步缩小范围。

通过 go list -deps -json 命令,可以得到一个仓库具体的 import 分析,也就是下面的 Package 列表(部分字段省略)。

type Package struct {
	ImportPath string   // import path of package in dir
	Standard   bool     // is this package part of the standard Go library?
	Module     Module   // info about package's module, if any
	Imports    []string // import paths used by this package
}

type Module struct {
	Path    string // module path
	Version string // module version
	Main    bool   // is this the main module?
}
  1. 构建一个有向图,对于上面得到的 Package 列表,将所有 Package.ImportPath 加入节点。

  2. Module.Main 为 true 的节点标记为起始节点;将 Module.Path 属于需要下线的依赖库的节点标记为目标节点

  3. 对于每个 Package,以 Package.ImportPath 为起点,每个 Package.Imports 中的元素为终点,建立一条边。

  4. 对于每个起始节点,查找它到目标节点的路径。如果路径存在,则说明 import path 链路上存在目标依赖库,此仓库有安全风险;否则,继续用其它起始节点执行该步骤,如果所有起始节点都找不到路径,则说明 import path 链路上不存在目标依赖库,仓库可视为安全。

此外,还可以加入白名单机制。比如,如果目标依赖库是由某个特定 Package 引入的,这种情况可接受,那么可以在第3步建立边时进行过滤,如果 Module.Path 属于这个特定 Package,则不建立边。这时第4步就找不到这个特定 Package 到目标依赖库的链路。

Updated: