代码检查工具
代码检查通常会被配置再 CI 中,用于自动检查代码的质量,本次我们介绍三个用于代码检查的工具
- go vet / go tool vet
- golangci-lint
- govulncheck
go vet / go tool vet
go vet 命令是 go tool vet 的简单封装,go vet 实际上还是需要调用 go tool vet 才能完成工作,这俩命令的主要目的就是为了基础的代码检查。不过这个命令只能做简单的检查,下面我们介绍一下更常用的工具。
golangci-lint
首先在介绍 golangci-lint 之前我们先下载它,它是一个 go 语言写的可执行文件,使用
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
即可下载到本地的~/go/bin/ 目录,这里专门存储使用 go install 下载的使用 go 写的可执行文件,记得将这个路径加入 PATH。
通过在要检查的项目中设置配置文件,用来配置 lint 工具的选项,使用 .golangci.yaml
即可
例如:
run:
skip-dirs: # 设置要忽略的目录
- util
- .*~
- api/swagger/docs
skip-files: # 设置不需要检查的go源码文件,支持正则匹配,这里建议包括:_test.go
- ".*\\.my\\.go$"
- _test.go
linters-settings:
errcheck:
check-type-assertions: true # 这里建议设置为true,如果确实不需要检查,可以写成`num, _ := strconv.Atoi(numStr)`
check-blank: false
gci:
# 将以`github.com/marmotedu/iam`开头的包放在第三方包后面
local-prefixes: github.com/marmotedu/iam
godox:
keywords: # 建议设置为BUG、FIXME、OPTIMIZE、HACK
- BUG
- FIXME
- OPTIMIZE
- HACK
goimports:
# 设置哪些包放在第三方包后面,可以设置多个包,逗号隔开
local-prefixes: github.com/marmotedu/iam
gomoddirectives: # 设置允许在go.mod中replace的包
replace-local: true
replace-allow-list:
- github.com/coreos/etcd
- google.golang.org/grpc
- github.com/marmotedu/api
- github.com/marmotedu/component-base
- github.com/marmotedu/marmotedu-sdk-go
gomodguard: # 下面是根据需要选择可以使用的包和版本,建议设置
allowed:
modules:
- gorm.io/gorm
- gorm.io/driver/mysql
- k8s.io/klog
domains: # List of allowed module domains
- google.golang.org
- gopkg.in
- golang.org
- github.com
- go.uber.org
blocked:
modules:
- github.com/pkg/errors:
recommendations:
- github.com/marmotedu/errors
reason: "`github.com/marmotedu/errors` is the log package used by marmotedu projects."
versions:
- github.com/MakeNowJust/heredoc:
version: "> 2.0.9"
reason: "use the latest version"
local_replace_directives: false
lll:
line-length: 240 # 这里可以设置为240,240一般是够用的
importas: # 设置包的alias,根据需要设置
jwt: github.com/appleboy/gin-jwt/v2
metav1: github.com/marmotedu/component-base/pkg/meta/v1
使用 golangci-lint run (等于 golangci-lint run ./... 意思就是把所有的包,子包,遍历完全) 你会得到一个类似:
collie.go:171:41: composites: image/jpeg.Options struct literal uses unkeyed fields (govet)
if err := jpeg.Encode(file, i.img, &jpeg.Options{q}); err != nil {
^
collie.go:241:2: printf: `fmt.Println` arg list ends with redundant newline (govet)
fmt.Println("声明:本程序来自GitHub:shgopher,欢迎关注公众号:科科人神;\n免费软件,如果使用期间出现任何后果,本软件不承担任何责任谢谢\n")
^
collie.go:244:2: printf: `fmt.Println` arg list ends with redundant newline (govet)
fmt.Println("运行结束 ☕️ ☕ ☕\n")
^
collie.go:162:5: SA9001: defers in this range loop won't run unless the channel gets closed (staticcheck)
defer file.Close()
^
这样的结果,这样你就会发现是哪个配置的 linter 发出的警告,以及是什么样子的警告。
govulncheck
go 官方维护了一个 https://vuln.go.dev/ 的漏洞库,我们可以使用 go install golang.org/x/vuln/cmd/govulncheck@latest
的方式,下载目前 (go 1.19) 还在测试阶段的这一功能,govulncheck
将会是一个独立的工具,并且 go 在 https://pkg.go.dev/golang.org/x/vuln/vulncheck 还提供了相关功能的 API,可以更灵活的去使用这个功能,目前已知的即将推出的功能分别是提供 vscode 插件,以及将此功能集成在 pkg.go.dev 这个 go 包的集合地,也就是说只要被收录在这个网站的 go 包都将自动接受漏洞检查,另外,go 以后可能还会将这个功能直接集成在例如 go build
这种常用命令上。
- 下载 govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest
- 在一个拥有 go.mod 的目录下,使用 govulncheck 跟上一个有 go 文件的路径,例如:
govulncheck ./pkg/watcher
只需要这样简单的设置就可以去检查代码中存在的风险和漏洞,govulncheck 就会打印出这样的信息:
Vulnerability #2: GO-2022-0493
When called with a non-zero flags parameter, the Faccessat
function can incorrectly report that a file is accessible.
Found in: golang.org/x/sys/unix@v0.0.0-20211020064051-0ec99a608a1b
Fixed in: golang.org/x/sys/unix@v0.0.0-20220412211240-33da011f77ad
More info: https://pkg.go.dev/vuln/GO-2022-0493
信息中包括了你引用的某些包出现的一些漏洞,在 fix 中有修复的信息,可以把你引用的包进行一个升级。
x/tools 工具系列
https://pkg.go.dev/golang.org/x/tools#section-readme
比如检测变量 shadow 的工具
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
参考资料
- https://go.dev/blog/vuln
- https://time.geekbang.org/column/article/390401