Linters
虽然IDE已经有插件可以执行静态代码分析,但golangci-lint依然有大量自定义Linter值得引入和执行静态代码扫描,提高代码质量
golangci-lint的Linters golangci-lint.run/usage/linte…
三方Linters github.com/golangci/aw…
以下为golangci-lint在VSCode中集成和使用,包括Linters以及Nilaway
.custom-gcl.yml文件
在项目工程根目录,创建/修改.golangci.yml文件
这里推荐一些Linter,以及对应配置,详见如下(涉及安全、风格、性能)
enable 启用的插件清单
linters-settings插件的配置
配置可复制直接使用
vim .golangci.yml
linters:
# Disable all linters.
# Default: false
disable-all: true
# Enable specific linter
# https://golangci-lint.run/usage/linters/#enabled-by-default-linters
enable:
# default linter
# deadcode被弃用, 请使用unused
#- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
# varcheck被弃用
#- varcheck
# 新增 linter
- gocyclo
- gofmt
- goimports
# 检查 HTTP 响应主体是否成功关闭。
- bodyclose
# 检查传递给 json 编码函数的类型。报告不支持的类型并报告可以省略对返回错误的检查的情况。
- errchkjson
# 对 Go“和类型”运行详尽性检查。
- gochecksumtype
# 查找即使检查错误不为零也会返回零的代码。
- nilerr
# 检查该函数是否使用非继承的上下文。
- contextcheck
# 检查 sql.Rows、sql.Stmt、sqlx.NamedStmt 和 pgx.Query 是否已关闭。
- sqlclosecheck
# 检查外部包返回的错误是否被包装。
- wrapcheck
# Copyloopvar 是一个用于检测循环变量被复制的地方的 linter。
- copyloopvar
# 前往 linter 检查错误处理表达式。
- err113
# 检查枚举 switch 语句的详尽性。
- exhaustive
# 检测长函数的工具。
- funlen
# 检查是否存在全局变量。
- gochecknoglobals
# 检查 Go 代码中不存在 init 函数。
- gochecknoinits
# 提供诊断功能,检查错误、性能和样式问题。通过动态规则无需重新编译即可扩展。动态规则以声明方式编写,包含 AST 模式、过滤器、报告消息和可选建议。
#- gocritic
# 检查源代码是否存在安全问题。
- gosec
# 强制使用一致的导入别名。
- importas
# Maintidx测量每个功能的可维护性指数。
- maintidx
# 报告深度嵌套的 if 语句。
- nestif
# 检查 fmt.Sprintf 是否可以被更快的替代方案取代。
- perfsprint
# 查找浪费的赋值语句。
- wastedassign
# - nilaway
# Run only fast linters from enabled linters set (first run won't be fast)
# Default: false
fast: true
linters-settings:
gocyclo:
# Minimal code complexity to report.
# Default: 30 (but we recommend 10-20)
min-complexity: 10
wrapcheck:
# An array of strings that specify substrings of signatures to ignore.
# If this set, it will override the default set of ignored signatures.
# See https://github.com/tomarrell/wrapcheck#configuration for more information.
# Default: [".Errorf(", "errors.New(", "errors.Unwrap(", "errors.Join(", ".Wrap(", ".Wrapf(", ".WithMessage(", ".WithMessagef(", ".WithStack("]
ignoreSigs:
- .Errorf(
- errors.New(
- errors.Unwrap(
- errors.Join(
- .Wrap(
- .Wrapf(
- .WithMessage(
- .WithMessagef(
- .WithStack(
# An array of strings that specify regular expressions of signatures to ignore.
# Default: []
ignoreSigRegexps:
- \.New.*Error\(
# An array of strings that specify globs of packages to ignore.
# Default: []
ignorePackageGlobs:
- encoding/*
- github.com/pkg/*
# An array of strings that specify regular expressions of interfaces to ignore.
# Default: []
ignoreInterfaceRegexps:
- ^(?i)c(?-i)ach(ing|e)
gosec:
# To select a subset of rules to run.
# Available rules: https://github.com/securego/gosec#available-rules
# Default: [] - means include all rules
includes:
- G101 # Look for hard coded credentials
- G102 # Bind to all interfaces
- G103 # Audit the use of unsafe block
- G104 # Audit errors not checked
- G106 # Audit the use of ssh.InsecureIgnoreHostKey
- G107 # Url provided to HTTP request as taint input
- G108 # Profiling endpoint automatically exposed on /debug/pprof
- G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32
- G110 # Potential DoS vulnerability via decompression bomb
- G111 # Potential directory traversal
- G112 # Potential slowloris attack
- G113 # Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772)
- G114 # Use of net/http serve function that has no support for setting timeouts
- G115 # Potential integer overflow when converting between integer types
- G201 # SQL query construction using format string
- G202 # SQL query construction using string concatenation
- G203 # Use of unescaped data in HTML templates
- G204 # Audit use of command execution
- G301 # Poor file permissions used when creating a directory
- G302 # Poor file permissions used with chmod
- G303 # Creating tempfile using a predictable path
- G304 # File path provided as taint input
- G305 # File traversal when extracting zip/tar archive
- G306 # Poor file permissions used when writing to a new file
- G307 # Poor file permissions used when creating a file with os.Create
- G401 # Detect the usage of MD5 or SHA1
- G402 # Look for bad TLS connection settings
- G403 # Ensure minimum RSA key length of 2048 bits
- G404 # Insecure random number source (rand)
- G405 # Detect the usage of DES or RC4
- G406 # Detect the usage of MD4 or RIPEMD160
- G501 # Import blocklist: crypto/md5
- G502 # Import blocklist: crypto/des
- G503 # Import blocklist: crypto/rc4
- G504 # Import blocklist: net/http/cgi
- G505 # Import blocklist: crypto/sha1
- G506 # Import blocklist: golang.org/x/crypto/md4
- G507 #Import blocklist: golang.org/x/crypto/ripemd160
- G601 # Implicit memory aliasing of items from a range statement
- G602 # Slice access out of bounds
# To specify a set of rules to explicitly exclude.
# Available rules: https://github.com/securego/gosec#available-rules
# Default: []
excludes:
- G101 # Look for hard coded credentials
- G102 # Bind to all interfaces
- G103 # Audit the use of unsafe block
- G104 # Audit errors not checked
- G106 # Audit the use of ssh.InsecureIgnoreHostKey
- G107 # Url provided to HTTP request as taint input
- G108 # Profiling endpoint automatically exposed on /debug/pprof
- G109 # Potential Integer overflow made by strconv.Atoi result conversion to int16/32
- G110 # Potential DoS vulnerability via decompression bomb
- G111 # Potential directory traversal
- G112 # Potential slowloris attack
- G113 # Usage of Rat.SetString in math/big with an overflow (CVE-2022-23772)
- G114 # Use of net/http serve function that has no support for setting timeouts
- G115 # Potential integer overflow when converting between integer types
- G201 # SQL query construction using format string
- G202 # SQL query construction using string concatenation
- G203 # Use of unescaped data in HTML templates
- G204 # Audit use of command execution
- G301 # Poor file permissions used when creating a directory
- G302 # Poor file permissions used with chmod
- G303 # Creating tempfile using a predictable path
- G304 # File path provided as taint input
- G305 # File traversal when extracting zip/tar archive
- G306 # Poor file permissions used when writing to a new file
- G307 # Poor file permissions used when creating a file with os.Create
- G401 # Detect the usage of MD5 or SHA1
- G402 # Look for bad TLS connection settings
- G403 # Ensure minimum RSA key length of 2048 bits
- G404 # Insecure random number source (rand)
- G405 # Detect the usage of DES or RC4
- G406 # Detect the usage of MD4 or RIPEMD160
- G501 # Import blocklist: crypto/md5
- G502 # Import blocklist: crypto/des
- G503 # Import blocklist: crypto/rc4
- G504 # Import blocklist: net/http/cgi
- G505 # Import blocklist: crypto/sha1
- G506 # Import blocklist: golang.org/x/crypto/md4
- G507 #Import blocklist: golang.org/x/crypto/ripemd160
- G601 # Implicit memory aliasing of items from a range statement
- G602 # Slice access out of bounds
# Exclude generated files
# Default: false
exclude-generated: true
# Filter out the issues with a lower severity than the given value.
# Valid options are: low, medium, high.
# Default: low
severity: medium
# Filter out the issues with a lower confidence than the given value.
# Valid options are: low, medium, high.
# Default: low
confidence: medium
# Concurrency value.
# Default: the number of logical CPUs usable by the current process.
concurrency: 12
# To specify the configuration of rules.
config:
# Globals are applicable to all rules.
global:
# If true, ignore #nosec in comments (and an alternative as well).
# Default: false
nosec: true
# Add an alternative comment prefix to #nosec (both will work at the same time).
# Default: ""
"#nosec": "#my-custom-nosec"
# Define whether nosec issues are counted as finding or not.
# Default: false
show-ignored: true
# Audit mode enables addition checks that for normal code analysis might be too nosy.
# Default: false
audit: true
G101:
# Regexp pattern for variables and constants to find.
# Default: "(?i)passwd|pass|password|pwd|secret|token|pw|apiKey|bearer|cred"
pattern: "(?i)example"
# If true, complain about all cases (even with low entropy).
# Default: false
ignore_entropy: false
# Maximum allowed entropy of the string.
# Default: "80.0"
entropy_threshold: "80.0"
# Maximum allowed value of entropy/string length.
# Is taken into account if entropy >= entropy_threshold/2.
# Default: "3.0"
per_char_threshold: "3.0"
# Calculate entropy for first N chars of the string.
# Default: "16"
truncate: "32"
# Additional functions to ignore while checking unhandled errors.
# Following functions always ignored:
# bytes.Buffer:
# - Write
# - WriteByte
# - WriteRune
# - WriteString
# fmt:
# - Print
# - Printf
# - Println
# - Fprint
# - Fprintf
# - Fprintln
# strings.Builder:
# - Write
# - WriteByte
# - WriteRune
# - WriteString
# io.PipeWriter:
# - CloseWithError
# hash.Hash:
# - Write
# os:
# - Unsetenv
# Default: {}
G104:
fmt:
- Fscanf
G111:
# Regexp pattern to find potential directory traversal.
# Default: "http\\.Dir\\(\"\\/\"\\)|http\\.Dir\\('\\/'\\)"
pattern: "custom\\.Dir\\(\\)"
# Maximum allowed permissions mode for os.Mkdir and os.MkdirAll
# Default: "0750"
G301: "0750"
# Maximum allowed permissions mode for os.OpenFile and os.Chmod
# Default: "0600"
G302: "0600"
# Maximum allowed permissions mode for os.WriteFile and ioutil.WriteFile
# Default: "0600"
G306: "0600"
# gocritic:
# # Disable all checks.
# # Default: false
# #disable-all: true
# # Which checks should be enabled in addition to default checks; can't be combined with 'disabled-checks'.
# # By default, list of stable checks is used (https://go-critic.github.io/overview#checks-overview):
# # appendAssign, argOrder, assignOp, badCall, badCond, captLocal, caseOrder, codegenComment, commentFormatting,
# # defaultCaseOrder, deprecatedComment, dupArg, dupBranchBody, dupCase, dupSubExpr, elseif, exitAfterDefer,
# # flagDeref, flagName, ifElseChain, mapKey, newDeref, offBy1, regexpMust, singleCaseSwitch, sloppyLen,
# # sloppyTypeAssert, switchTrue, typeSwitchVar, underef, unlambda, unslice, valSwap, wrapperFunc
# # To see which checks are enabled run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic`.
# #enabled-checks:
# #- nestingReduce
# #- unnamedResult
# #- ruleguard
# #- truncateCmp
# # Enable all checks.
# # Default: false
# enable-all: true
# # Which checks should be disabled; can't be combined with 'enabled-checks'.
# # Default: []
# #disabled-checks:
# # - regexpMust
# # Enable multiple checks by tags in addition to default checks.
# # Run `GL_DEBUG=gocritic golangci-lint run --enable=gocritic` to see all tags and checks.
# # See https://github.com/go-critic/go-critic#usage -> section "Tags".
# # Default: []
# #enabled-tags:
# #- diagnostic
# #- style
# #- performance
# #- experimental
# #- opinionated
# disabled-tags:
# - diagnostic
# - style
# - performance
# - experimental
# - opinionated
# # Settings passed to gocritic.
# # The settings key is the name of a supported gocritic checker.
# # The list of supported checkers can be find in https://go-critic.github.io/overview.
# settings:
# # Must be valid enabled check name.
# captLocal:
# # Whether to restrict checker to params only.
# # Default: true
# paramsOnly: false
# commentedOutCode:
# # Min length of the comment that triggers a warning.
# # Default: 15
# minLength: 50
# elseif:
# # Whether to skip balanced if-else pairs.
# # Default: true
# skipBalanced: false
# hugeParam:
# # Size in bytes that makes the warning trigger.
# # Default: 80
# sizeThreshold: 70
# ifElseChain:
# # Min number of if-else blocks that makes the warning trigger.
# # Default: 2
# minThreshold: 4
# nestingReduce:
# # Min number of statements inside a branch to trigger a warning.
# # Default: 5
# bodyWidth: 4
# rangeExprCopy:
# # Size in bytes that makes the warning trigger.
# # Default: 512
# sizeThreshold: 516
# # Whether to check test functions
# # Default: true
# skipTestFuncs: false
# rangeValCopy:
# # Size in bytes that makes the warning trigger.
# # Default: 128
# sizeThreshold: 32
# # Whether to check test functions.
# # Default: true
# skipTestFuncs: false
# ruleguard:
# # Enable debug to identify which 'Where' condition was rejected.
# # The value of the parameter is the name of a function in a ruleguard file.
# #
# # When a rule is evaluated:
# # If:
# # The Match() clause is accepted; and
# # One of the conditions in the Where() clause is rejected,
# # Then:
# # ruleguard prints the specific Where() condition that was rejected.
# #
# # The option is passed to the ruleguard 'debug-group' argument.
# # Default: ""
# debug: 'emptyDecl'
# # Determines the behavior when an error occurs while parsing ruleguard files.
# # If flag is not set, log error and skip rule files that contain an error.
# # If flag is set, the value must be a comma-separated list of error conditions.
# # - 'all': fail on all errors.
# # - 'import': ruleguard rule imports a package that cannot be found.
# # - 'dsl': gorule file does not comply with the ruleguard DSL.
# # Default: ""
# failOn: dsl,import
# # Comma-separated list of file paths containing ruleguard rules.
# # If a path is relative, it is relative to the directory where the golangci-lint command is executed.
# # The special '${configDir}' variable is substituted with the absolute directory containing the golangci config file.
# # Glob patterns such as 'rules-*.go' may be specified.
# # Default: ""
# rules: '${configDir}/ruleguard/rules-*.go,${configDir}/myrule1.go'
# # Comma-separated list of enabled groups or skip empty to enable everything.
# # Tags can be defined with # character prefix.
# # Default: "<all>"
# enable: "myGroupName,#myTagName"
# # Comma-separated list of disabled groups or skip empty to enable everything.
# # Tags can be defined with # character prefix.
# # Default: ""
# disable: "myGroupName,#myTagName"
# tooManyResultsChecker:
# # Maximum number of results.
# # Default: 5
# maxResults: 10
# truncateCmp:
# # Whether to skip int/uint/uintptr types.
# # Default: true
# skipArchDependent: false
# underef:
# # Whether to skip (*x).method() calls where x is a pointer receiver.
# # Default: true
# skipRecvDeref: false
# unnamedResult:
# # Whether to check exported functions.
# # Default: false
# checkExported: true
exhaustive:
# Program elements to check for exhaustiveness.
# Default: [ switch ]
check:
- switch
- map
# Check switch statements in generated files also.
# Default: false
check-generated: true
# Presence of "default" case in switch statements satisfies exhaustiveness,
# even if all enum members are not listed.
# Default: false
default-signifies-exhaustive: true
# Enum members matching the supplied regex do not have to be listed in
# switch statements to satisfy exhaustiveness.
# Default: ""
ignore-enum-members: "Example.+"
# Enum types matching the supplied regex do not have to be listed in
# switch statements to satisfy exhaustiveness.
# Default: ""
ignore-enum-types: "Example.+"
# Consider enums only in package scopes, not in inner scopes.
# Default: false
package-scope-only: true
# Only run exhaustive check on switches with "//exhaustive:enforce" comment.
# Default: false
explicit-exhaustive-switch: true
# Only run exhaustive check on map literals with "//exhaustive:enforce" comment.
# Default: false
explicit-exhaustive-map: true
# Switch statement requires default case even if exhaustive.
# Default: false
default-case-required: true
errchkjson:
# With check-error-free-encoding set to true, errchkjson does warn about errors
# from json encoding functions that are safe to be ignored,
# because they are not possible to happen.
#
# if check-error-free-encoding is set to true and errcheck linter is enabled,
# it is recommended to add the following exceptions to prevent from false positives:
#
# linters-settings:
# errcheck:
# exclude-functions:
# - encoding/json.Marshal
# - encoding/json.MarshalIndent
#
# Default: false
check-error-free-encoding: true
# Issue on struct encoding that doesn't have exported fields.
# Default: false
report-no-exported: false
# custom:
# nilaway:
# type: "module"
# description: Static analysis tool to detect potential nil panics in Go code.
# settings:
# # Settings must be a "map from string to string" to mimic command line flags: the keys are
# # flag names and the values are the values to the particular flags.
# include-pkgs: "<YOUR_PACKAGE_PREFIXES>"
# # NilAway can be referred to as `nilaway` just like any other golangci-lint analyzers in other
# # parts of the configuration file.
settings.json文件
如果是远程开发,则修改的是远程IDE配置
默认为/root/.vscode-server/data/Machine/settings.json
vim /root/.vscode-server/data/Machine/settings.json
增加
"go.lintTool": "golangci-lint",
"go.lintFlags": [
"--fast"
],
执行Lint Workspace
cmd+shift+p
即可展示相关err/warn
Nilaway
编译期间扫描nil空指针问题,避免大多数情况下的panic
根据官网说明:暂时不支持直接嵌入分析驱动器成为Linter,只能单独运行
但另类方法是:使用 golangci-lint custom -v自动生成附带自定义model的二进制golangci-lint(详见方案2)
个人,还是推荐直接执行(方案1)
方案1直接执行扫描
以独立命令执行扫描
go install go.uber.org/nilaway/cmd/nilaway@latest
直接扫描空指针
nilaway ./...
方案2编译构造自定义golangci-lint
核心是,构建为包括自定义插件的二进制golangci-lint
生成的二进制可独立执行,但多次试验后发现暂时并不能作为VSCode中go.lintTool的默认工具
.custom-gcl.yml
在项目工程根目录,创建/修改.custom-gcl.yml 文件
vim .custom-gcl.yml
version: v1.57.0
plugins:
- module: "go.uber.org/nilaway"
import: "go.uber.org/nilaway/cmd/gclplugin"
version: latest # Or a fixed version for reproducible builds.
.golangci.yml
在项目工程根目录,创建/修改.golangci.yml 文件
vim .golangci.yml
linters-settings:
custom:
nilaway:
type: "module"
description: Static analysis tool to detect potential nil panics in Go code.
settings:
# Settings must be a "map from string to string" to mimic command line flags: the keys are
# flag names and the values are the values to the particular flags.
include-pkgs: "<YOUR_PACKAGE_PREFIXES>"
# NilAway can be referred to as `nilaway` just like any other golangci-lint analyzers in other
# parts of the configuration file.
关于golangci-lint插件系统介绍
golangci-lint custom -v
会生成custom-gcl 二进制文件
执行./custom-gcl
生成后的二进制文件,如果成功在enable中,应该能看到nilaway被启用
./custom-gcl
和执行golangci-lint 结果差异在于包括了自定义的插件
./custom-gcl linters
会看到enable中增加了nilaway
./custom-gcl run
同原生./golangci-lint 执行效果一致