Gometalinter工具集成了目前绝大多数Golang代码检查工具,精心进行了规则分类和汉化,支持检测安全问题、无用代码、最佳实践、编码规范等66种告警类型。该工程以容器方式,对Gometalinter工具进行封装,并定义标准输入和输出。从而保证CodeCC平台数据解析模版化。
docker: 镜像打包文件Dockerfile路径
node_modules: node模块路径
sdk:适配工具脚步路径
sotfware:安装包路径
tool: 工具二进制路径
third_rules: 自定义规则扩展目录
gometalinter: v2
打包命令:docker build -t goml_scan:latest -f ./docker/Dockerfile .
{"projName":"DEVOPS_866A3D9D5DE99C24","scanPath":"/data/iegci/test_tool/test_code/rate_limit_center","whitePathList":[],"scanType":"full","skipPaths":["./\.svn/.","./\.git/.","./\.git","./third/.","./.git/.*"],"incrementalFiles":[],"openCheckers":[{"checkerName":"golint/funcret","nativeChecker":true},{"checkerName":"golint/fnsize","nativeChecker":true,"checkerOptions":[{"checkerOptionName":"fnsize","checkerOptionValue":"80"}]}]}
| 字段名 | 说明 | 举例 |
|---|---|---|
| projName | 项目名称 | DEVOPS_214A69F1F4F935DE |
| scanPath | 待扫描的路径,此处需使用绝对路径 | /data/project/code |
| whitePathList | 指定扫描路径列表(白名单) | /data/project/code/src |
| scanType | 进行全量或增量检查 | full或increment |
| skipPaths | 屏蔽路径正则表达式列表(黑名单) | [".*/demo/.*", ".*/protobuf/.*"] |
| incrementalFiles | 增量扫描的文件清单,清单为空表示全量扫描 | ["/data/project/code/src/main.go", "/data/project/code/src/test.go"]] |
| openCheckers | 打开的规则列表 | [{"checkerName":"golint/funcret","nativeChecker":true},{"checkerName":"golint/fnsize","nativeChecker":true,"checkerOptions":[{"checkerOptionName":"fnsize","checkerOptionValue":"80"}] |
| checkerName | 规则名称, 参考附2 | golint/funcret |
| nativeChecker | 是否工具默认规则 | true |
docker run -it goml_scan:latest /bin/bash -c "cd /usr/codecc/tool_scan; python3 ./sdk/src/scan.py --input=/data/input.json --output=/data/output.json"
{"defects":[{"checkerName":"golint/structcomment","description":"\u7ed3\u6784\u4f53\u9700\u8981\u6709\u6ce8\u91ca\u8bf4\u660e","filePath":"/data/iegci/test_tool/test_code/rate_limit_center/internal/dao/DCacheIndexDAO.go","line":"31"},{"checkerName":"golint/interfacecomment","description":"\u63a5\u53e3\u9700\u8981\u6709\u6ce8\u91ca\u8bf4\u660e","filePath":"/data/iegci/test_tool/test_code/rate_limit_center/internal/dao/InterfaceDAO.go","line":"34"}]}
| 字段名 | 说明 |
|---|---|
| defects | 告警列表 |
| filePath | 文件路径 |
| line | 文件行 |
| checkerName | 规则名称 |
| description | 规则描述 |
以下为语言对应数字,如果项目存在多语言,则数字相加:
| 数字 | 对应语言 |
|---|---|
| 1 | cs |
| 2 | cpp |
| 4 | java |
| 8 | php |
| 16 | objectivec |
| 32 | python |
| 64 | js |
| 128 | ruby |
| 512 | go |
| 1024 | swift |
| 4096 | kotlin |
| 规则名 | 规则描述 | 适用语言 |
|---|---|---|
| deadcode/unused | %s 未使用的函数 | Golang |
| errcheck/retvalue | 没有检查返回值 | Golang |
| gas/calls | 审查不安全的调用 | Golang |
| gas/crypto | 1、crypto/rc4已被列入import的黑名单中; 2、硬编码凭证; 3、crypto/md5已被列入import的黑名单中; 4、使用了弱的加密方法; 5、RSA Key至少应该有%d位(bits); 6、crypto/des已被列入import的黑名单中; 7、使用弱的数字随机生成器(使用math/rand,而不是crypto/rand); |
Golang |
| gas/error | 没有处理错误 | Golang |
| gas/escape | 该方法不会自动转义HTML。验证数据格式良好。 | Golang |
| gas/file | 在tmp目录创建文件没有使用ioutil.Tempfile | Golang |
| gas/httpoxy | net/http/cgi已被列入import的黑名单中:Go版本低于1.6.3容易受到Httpoxy的攻击:(CVE-2016-5386); | Golang |
| gas/modulus | 检查模数是否为0 | Golang |
| gas/network | 绑定了所有网络接口 | Golang |
| gas/permission | 1、文件至少需要%#o的权限; 2、目录至少需要%#o的权限; |
Golang |
| gas/sql | 1、使用了SQL字符拼接; 2、使用了SQL字符格式化; |
Golang |
| gas/subprocess | 1、子进程启动时传入了部分路径; 2、检查子进程的启动; 3、子进程启动使用了变量参数; 4、子进程启动时传入了变量; |
Golang |
| gas/tls | 1、PreferServerCipherSuites设为false; 2、MinVersion太低; 3、InsecureSkipVerify设为true; 4、InsecureSkipVerify可能为true; 5、MaxVersion太低; 6、MinVersion可能太低; 7、PreferServerCipherSuites可能为false; 8、MaxVersion可能太低; |
Golang |
| goconst/string | 重复使用的字符串应提取为常量:在 %s:%d:%d:%d 也使用了字符串 "%s",文件为: %s | Golang |
| gofmt/notformat | 文件没有使用 gofmt -s 格式化 | Golang |
| goimports/notimport | 文件没有被goimport | Golang |
| golint/args | context.Context应该是函数的第一个参数 | Golang |
| golint/comment | 1、exported类型%s %s应该有它自己的声明; 2、exported类型变量应该有注释,或者改成非exported类型; 3、exported类型 %s %s应该有注释%s,或者设置为unexported类型; 4、exported类型 %s %s应该有注释,或者设置为unexported类型; 5、在exported类型 %v的注释,形式应该是%v…; 6、在exported类型%s %s的注释,形式应该是%s…; |
Golang |
| golint/convar | 常量需要是全部大写 | Golang |
| golint/decl | 1、应该丢弃 = %s,从变量%s声明中;它的值为0; 2、应该省略类型%s,从变量%s声明中;它会从右手边推断出来; |
Golang |
| golint/equivalent | 应该省略range的第二个值;这个循环等效于for %s %s range ... |
Golang |
| golint/fnsize | 检查函数体行数(逻辑代码行+注释行)是否超过设定值,默认80行 | Golang |
| golint/funccomment | 函数需要有注释说明 | Golang |
| golint/funcpara | 函数参数的首字母需要小写 | Golang |
| golint/funcret | 函数返回参数首字母需要小写 | Golang |
| golint/interfacecomment | 接口需要有注释说明 | Golang |
| golint/naming | 1、%s 名称会被其他packages以 %s.%s引用,可以考虑这样调用 %s; 2、error变量%s应该以%sFoo形式命名; 3、Go名称不应该使用全部大写,请使用驼峰格式; 4、Go名称不应该使用k开头;%s %s应该是%s; 5、%s %s 应该是 %s; 6、receiver名称不应该有下划线,如果是不使用的,可以省略; 7、receiver名称应该是其身份的反射;不要使用this或者self; 8、receiver名称%s应该与之前的%s %s保持一致; 9、Go名称不应该使用下划线;%s %s应该是%s; |
Golang |
| golint/nogoto | 业务代码禁止使用goto,其他框架或底层源码推荐尽量不用 | Golang |
| golint/noptr | 不建议map、chan类型使用指针类型 | Golang |
| golint/package | 1、package注释开头不应该有空格; 2、空的import应只能在main或test package里面,或者使用注释说明; 3、package需要写注释; 4、不应该使用 . imports 形式; 5、package注释与声明之间不应该有空行; 6、package名称不应该有下划线; 7、package注释应该是该种形式 %s; |
Golang |
| golint/print | %s(fmt.Sprintf(...)) 不符合要求,应该使用 %s.Errorf(...)替换之 | Golang |
| golint/replace | 应该替换%s以%s%s | Golang |
| golint/ret | 1、当返回多个值时,错误值应该放到最后; 2、exported类型 %s %s 返回unexported类型 %s,这会造成使用上的困扰; 3、if语块以return语句结束,那么可以删去else分支并将else内的语句移到if语块外; |
Golang |
| golint/string | 错误字符串不应该大写,或者标点符号、新行结尾 | Golang |
| golint/structcomment | 结构体需要有注释说明 | Golang |
| golint/todo | 检测注释中出现的todo单词 | Golang |
| golint/type | 1、不应该使用基础类型 %s 作为context.WithValue的key; 2、var %s 是类型 %v,不要使用unit-specific后缀 %q; |
Golang |
| gosimple/boolcmp | 应该省略bool常量的比较,可以简化为:%s | Golang |
| gosimple/copy | 应该使用copy()而不是循环 | Golang |
| gosimple/for | 应该使用for range,而不是 for select{} | Golang |
| gosimple/sendrecv | 应该使用简单通道的send/receive,而不是select | Golang |
| gosimple/usageadvice | 1、应该转换 %s(类型为%s)到%s,而不是使用struct结构; 2、应该使用 for {} 而不是 for true {}; 3、不必要的nil检查; 4、应该使用原生字符串 ( ...)及regexp.%s避免转义两次;5、应该使用无条件的 %s.%s 来替换这个if语句; 6、当 %s 为true时,%s不可能为nil; 7、应该写 %s 而不是 %s; 8、应该在新的一行里合并变量的声明和赋值; 9、多余的break语句; 10、应该使用fmt.Errorf(...),而不是errors.New(fmt.Sprintf(...)); 11、应该省略nil检查;%s执行len()定义为0; 12、应该使用%s = append(%s, %s...) 来替换循环; 13、使用slice时应该省略第二个index,s[a:len(s)] 等效于 s[a:]; 14、应该使用time.Util,而不是t.Sub(time.Now()); 15、应该使用%v.String()方法而不是%v; 16、if %s != nil { return %s }; return %s' 可以简化为 'return %s'; 17、'_ = <-ch' 可以简化为 '<-ch'; 18、应该使用 'return ',而不是 'if { return }; return '; 19、应该使用String(),而不是fmt.Sprintf; 20、应该使用%v.Bytes()方法而不是%v; 21、应该使用 %s%s.%s(%s); 22、应该使用time.Since,而不是time.Now().Sub; 23、多余的return语句; 24、应该使用make(%s, %s); 25、应该使用%sbytes.Equal(%s); 26、应该使用make(%s); 27、参数已经是字符串,没有必要使用fmt.Sprintf; 28、应该使用copy(%s[:%s], %s[%s:]); 29、参数的基础类型是字符串,应该使用简单的转换而不是使用fmt.Sprintf; 30、应该省略range的值;这个循环等效与 for range ...; |
Golang |
| ineffassign/assign | 无效赋值:%s | Golang |
| interfacer/interface | %s 可以为 %s | Golang |
| maligned/size | %s:结构大小%d 可以为 %d | Golang |
| misspell/spell | %s 应拼写为 %s | Golang |
| nakedret/ret | 检查named return语句的函数体是否超过一定数值,默认是5行 | Golang |
| safesql/sql | 潜在不安全的SQL语句 | Golang |
| staticcheck/append | append的结果不会被使用,除非在其他的appends里 | Golang |
| staticcheck/args | 1、参数%s在使用前被覆写了; 2、该函数类似print风格的函数,有第一个动态参数,但没有其他更多的参数。应该使用print风格的函数。; 3、io.Seeker的第一个参数是偏移值offset,但是使用了io.Seek*常量; |
Golang |
| staticcheck/assign | 1、%s 自赋值为 %s; 2、赋值给nil map; 3、不应该赋值给%s; |
Golang |
| staticcheck/boolean | 对于boolean类型的双重否定是没有效果的,是笔误吗? | Golang |
| staticcheck/break | break语句没有效果,是希望跳出外部循环吗? | Golang |
| staticcheck/compare | 1、比较两个不同长度的字符串是否相等,会永远返回false; 2、无符号数不可能 < 0; 3、无符号数永远 >= 0; 4、x %s 0的结果永远等于x; 5、没有数值等于NaN,即使Nan本身; 6、x & 0的结果永远等于 0; |
Golang |
| staticcheck/condition | 这个条件多次出现在if/else if链中 | Golang |
| staticcheck/defer | 1、刚好在lock之后defer %s,你是想defer %s吗?; 2、defer %s 前,应该先检查返回的错误码; |
Golang |
| staticcheck/deprecated | %s 已经废弃:%s | Golang |
| staticcheck/efficient | m[string(key)] 可能比 k := string(key); m[k] 更加高效 | Golang |
| staticcheck/emptybranch | 空的分支 | Golang |
| staticcheck/exec | exec.Command的第一个参数看起来是shell命令,但是缺少了程序名或者路径 | Golang |
| staticcheck/exit | TestMain应该调用os.Exit来设置退出码 | Golang |
| staticcheck/exp | 1、%s操作符两边存在相同的表达式; 2、二元表达式永远是 %t,对于所有可能的值(%s %s %s); |
Golang |
| staticcheck/explicit | 只有第1个常量是显式类型 | Golang |
| staticcheck/finalizer | finalizer closes over the object, preventing the finalizer from ever running (at %s) | Golang |
| staticcheck/goroutine | goroutine调用T.%s,作为测试test必须在相同的goroutine里调用 | Golang |
| staticcheck/httpheader | 在http.Header里的keys都是规范化的,然而%q并不符合规范;修改该常量或者使用http.CanonicalHeaderKey | Golang |
| staticcheck/infinite | 调用了无限递归 | Golang |
| staticcheck/iowriter | io.Writer.Write 不能修改所提供的buffer缓冲区,即使是临时性的 | Golang |
| staticcheck/loop | 1、在range循环中,defers不会运行,除非通道被关闭; 2、循环变量没有变化; 3、循环条件一直没有变化,或者存在竞争条件; 4、外层循环无条件终止; 5、这个循环会spin,导致100%CPU的使用; 6、无限循环中的defers永远不会运行; 7、在for+select循环中不应该存在空的default case,会导致循环spin; |
Golang |
| staticcheck/overrun | index索引超出界限(bounds) | Golang |
| staticcheck/resource | 空的临界区(critical section) | Golang |
| staticcheck/return | %s 是一个纯函数(pure function),但是它的返回值被忽略了 | Golang |
| staticcheck/routine | 启动goroutine前应该先调用%s,以避免竞争 | Golang |
| staticcheck/signal | 1、%s 信号不能被捕获; 2、%s 不能被捕获(是syscall.SIGTERM吗?); |
Golang |
| staticcheck/simple | 1、文件模式 %s 计算结果是 %#o;是否应该是 0%s; 2、&*x 可以简化为 x。这个用法不会复制x。; |
Golang |
| staticcheck/sleep | 睡眠 %d(ns)很可能是一个bug。如果不是的话请明确下:%s | Golang |
| staticcheck/timeticker | 使用time.Tick在某些场景下会泄漏。可以考虑在endless function中使用,或者使用time.NewTicker。 | Golang |
| staticcheck/unused | 这个变量%s的值不会被使用 | Golang |
| structcheck/field | 未使用的struct字段 | Golang |
| tosa/comment_ratio | 腾讯开源注释率要求不少于10% | Golang |
| tosa/fn_length | 函数名长度限制 | Golang |
| tosa/indent | 缩进使用tab | Golang |
| tosa/license | 腾讯开源文件头需要包含开源协议信息 | Golang |
| tosa/linelength | 源码每一行字符数不能超过指定阈值,默认阈值为120 | Golang |
| tosa/newline | 源码文件禁止使用回车字符(CR) | Golang |
| tosa/utf8 | 文件编码必须是utf8 | Golang |
| unconvert/convert | 不必要的转换 | Golang |
| unparam/unused | 参数%s没有使用 | Golang |
| unparam/value | 1、参数始终接收%v; 2、参数%s始终是%s; |
Golang |
| unused/unused | %s没有被使用 | Golang |
| varcheck/unused | 未使用的全局变量 | Golang |
| vet/vet | 检测妨碍编译的错误 | Golang |
| vetshadow/shadow | %q的声明覆盖了%s位置的声明 | Golang |