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?
}
-
构建一个有向图,对于上面得到的 Package 列表,将所有
Package.ImportPath
加入节点。 -
将
Module.Main
为 true 的节点标记为起始节点;将Module.Path
属于需要下线的依赖库的节点标记为目标节点。 -
对于每个 Package,以
Package.ImportPath
为起点,每个Package.Imports
中的元素为终点,建立一条边。 -
对于每个起始节点,查找它到目标节点的路径。如果路径存在,则说明 import path 链路上存在目标依赖库,此仓库有安全风险;否则,继续用其它起始节点执行该步骤,如果所有起始节点都找不到路径,则说明 import path 链路上不存在目标依赖库,仓库可视为安全。
此外,还可以加入白名单机制。比如,如果目标依赖库是由某个特定 Package 引入的,这种情况可接受,那么可以在第3步建立边时进行过滤,如果 Module.Path
属于这个特定 Package,则不建立边。这时第4步就找不到这个特定 Package 到目标依赖库的链路。