diff --git a/DEV_GUIDE.md b/DEV_GUIDE.md index cb1ffabdb..2f440d0f6 100644 --- a/DEV_GUIDE.md +++ b/DEV_GUIDE.md @@ -34,8 +34,8 @@ ### 开发工具 ```bash -# golangci-lint(CI 用 v2.9,本地建议装同一版以免版本差异带来的噪音) -go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.9 +# golangci-lint(CI 用 v2.13,本地建议装同一版以免版本差异带来的噪音) +go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.13 # pnpm (前端包管理) npm install -g pnpm @@ -47,7 +47,7 @@ npm install -g pnpm | Workflow | 触发条件 | 检查内容 | |----------|----------|----------| -| **backend-ci.yml** | push, pull_request | 单元测试 + 集成测试 + golangci-lint v2.9 | +| **backend-ci.yml** | push, pull_request | 单元测试 + 集成测试 + golangci-lint v2.13 | | **security-scan.yml** | push, pull_request, 每周一 | govulncheck + gosec + pnpm audit | | **release.yml** | tag `v*` | 构建发布(PR 不触发) | diff --git a/backend/.golangci.yml b/backend/.golangci.yml index a4aed1147..08d1b61f4 100644 --- a/backend/.golangci.yml +++ b/backend/.golangci.yml @@ -57,10 +57,6 @@ linters: - G304 - G306 - G404 - # G703/G704 是 G304/G107 的污点分析版:网关本职就是按配置转发到上游 URL、按配置写本地文件, - # 污点来源即配置本身,规则不适用。 - - G703 - - G704 severity: high confidence: high errcheck: @@ -125,6 +121,16 @@ linters: # Default: true — must be true, ent generates 130K+ lines of code generated-is-used: true + exclusions: + rules: + # G703/G704 污点分析在测试文件中只会命中 httptest mock 与测试者自设的 + # 环境变量路径,不构成攻击面;且该分析跨环境结果不稳定(本地/CI 报告的 + # 位置集合不同),逐点 nolint 无法收敛,故按路径豁免。生产代码不豁免, + # 必须逐点 //nolint:gosec 并写明信任边界。 + - path: '_test\.go$' + linters: [ gosec ] + text: 'G70[34]' + formatters: enable: - gofmt diff --git a/backend/internal/pkg/servertiming/http.go b/backend/internal/pkg/servertiming/http.go index e326e2430..2ad8a04ae 100644 --- a/backend/internal/pkg/servertiming/http.go +++ b/backend/internal/pkg/servertiming/http.go @@ -53,10 +53,10 @@ func Do(client *http.Client, req *http.Request) (*http.Response, error) { client = http.DefaultClient } if req == nil || !Active(req.Context()) { - return client.Do(req) + return client.Do(req) //nolint:gosec // G704: 通用埋点包装器,不构造 URL;请求由调用方构造,SSRF 信任边界在调用方 } startedAt := time.Now() - response, err := client.Do(req) + response, err := client.Do(req) //nolint:gosec // G704: 同上 RecordDependency(req.Context(), dependencyModule(req), startedAt, time.Now()) return response, err } diff --git a/backend/internal/service/gateway_service.go b/backend/internal/service/gateway_service.go index 0c0140b33..37bab2f97 100644 --- a/backend/internal/service/gateway_service.go +++ b/backend/internal/service/gateway_service.go @@ -1520,19 +1520,19 @@ func (s *GatewayService) initDebugGatewayBodyFile(path string) { } // 如果 path 指向一个已存在的目录,自动追加默认文件名 - if info, err := os.Stat(path); err == nil && info.IsDir() { + if info, err := os.Stat(path); err == nil && info.IsDir() { //nolint:gosec // G703: path 仅来自启动环境变量 SUB2API_DEBUG_GATEWAY_BODY(运维配置),非请求输入 path = filepath.Join(path, debugGatewayBodyDefaultFilename) } // 确保父目录存在 if dir := filepath.Dir(path); dir != "." { - if err := os.MkdirAll(dir, 0755); err != nil { + if err := os.MkdirAll(dir, 0755); err != nil { //nolint:gosec // G703: 同上 slog.Error("failed to create gateway debug log directory", "dir", dir, "error", err) return } } - f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) //nolint:gosec // G703: 同上 if err != nil { slog.Error("failed to open gateway debug log file", "path", path, "error", err) return diff --git a/backend/internal/service/pricing_service.go b/backend/internal/service/pricing_service.go index f7733ae00..6ae24dd39 100644 --- a/backend/internal/service/pricing_service.go +++ b/backend/internal/service/pricing_service.go @@ -596,7 +596,7 @@ func (s *PricingService) useFallbackPricing() error { } pricingFile := s.getPricingFilePath() - if err := os.WriteFile(pricingFile, data, 0644); err != nil { + if err := os.WriteFile(pricingFile, data, 0644); err != nil { //nolint:gosec // G703: 路径为配置的数据目录 + 硬编码文件名,非请求输入 logger.LegacyPrintf("service.pricing", "[Pricing] Failed to copy fallback: %v", err) }