ECC 的 Go 代码审查指南:用 /go-review 命令与 go-reviewer 代理实现惯用化、并发安全、错误处理与安全合规审查
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
导读
本文基于 ECC(The agent harness performance optimization system,面向 Claude Code、Codex、Opencode、Cursor 等环境的 Agent 工作台)中的/go-review命令文档,系统讲解如何借助go-reviewer代理对 Go 代码执行一次覆盖惯用模式(idiomatic patterns)、并发安全性(concurrency safety)、错误处理(error handling)与安全性(security)的全维度代码审查。你将掌握该命令的完整工作流程、CRITICAL/HIGH/MEDIUM 三级问题分类标准、实际运行的静态分析工具链,以及如何把审查结果与合并审批决策(PASS/WARNING/FAIL)衔接起来,从而在提交前拦截竞态条件、goroutine 泄漏、注入漏洞等高风险缺陷。
命令定位:/go-review 在 ECC 中的角色
在 ECC 的命令体系中,/go-review是面向 Go 代码的专用审查命令,其作用在于调用仓库中的go-reviewer代理(Agent 定义见 agents/go-reviewer.md),执行一次"Go 特有"而非泛化的代码评审。与通用评审命令/code-review相比,它的检查维度完全围绕 Go 语言特性设计:goroutine 安全、channel 使用、mutex 模式、errors.Is/As错误链、接口设计、表驱动测试等。
该命令文档(英文原版见 commands/go-review.md,日文版见 docs/ja-JP/commands/go-review.md)描述的六步工作流为:
- 识别 Go 变更:通过
git diff找出被修改的.go文件; - 运行静态分析:依次执行
go vet、staticcheck、golangci-lint; - 安全扫描:检查 SQL 注入、命令注入、竞态条件;
- 并发审查:分析 goroutine 安全性、channel 用法、mutex 模式;
- 惯用 Go 检查:确认代码符合 Go 惯例与最佳实践;
- 生成报告:按严重程度对问题进行归类输出。
何时使用 /go-review
命令文档给出了明确的适用场景,以下任一情况都应当调用/go-review:
- 编写或修改了 Go 代码之后;
- 提交 Go 变更之前(作为提交前质量门禁);
- 审查包含 Go 代码的 Pull Request 时;
- 加入一个新的 Go 代码库进行 onboarding 时;
- 学习惯用 Go 模式时(可将审查报告当作反馈教材)。
在 go-reviewer 代理的说明中,调用时还会遵循固定的启动流程:先运行git diff -- '*.go'查看近期 Go 文件变更,再运行go vet ./...与可用的staticcheck ./...,聚焦于被修改的.go文件立即开始审查。这意味着命令的核心输入是"变更集",而不是整个仓库,能显著控制审查噪音并聚焦增量风险。
三级问题分类体系详解
/go-review将发现的问题分为CRITICAL(必须修复)、HIGH(建议修复)、MEDIUM(考虑修复)三档。go-reviewer 代理在 agents/go-reviewer.md 中给出了比命令文档更细粒度的分类依据,两者互为补充:
CRITICAL —— 安全问题
命令文档列出:SQL/命令注入漏洞、无同步的竞态条件、goroutine 泄漏、硬编码凭证、不安全的指针使用、关键路径上忽略错误。
代理进一步细化了安全维度的判定依据:
- SQL 注入:在
database/sql查询中使用字符串拼接; - 命令注入:
os/exec中使用了未经验证的输入; - 路径遍历:用户可控文件路径未经
filepath.Clean+ 前缀校验; - 竞态条件:共享状态没有同步机制;
- unsafe 包:无充分理由地使用
unsafe; - 硬编码密钥:源码中出现 API Key、密码;
- 不安全 TLS:
InsecureSkipVerify: true。
CRITICAL —— 错误处理
- 忽略错误:用
_丢弃错误返回值; - 缺少错误包装:直接
return err,而非fmt.Errorf("context: %w", err); - 对可恢复错误使用 panic:应当返回 error;
- 未使用 errors.Is/As:用
err == target比较错误,而非errors.Is(err, target)。
HIGH —— 并发
- goroutine 泄漏:没有取消机制(应使用
context.Context); - 无缓冲 channel 死锁:发送方没有接收方;
- 缺少 sync.WaitGroup:goroutine 之间没有协调;
- mutex 误用:未使用
defer mu.Unlock()。
HIGH —— 代码质量
- 函数过大:超过 50 行;
- 嵌套过深:超过 4 层;
- 非惯用写法:用
if/else而非提前返回(early return); - 包级变量:可变的全局状态;
- 接口污染:定义了未使用的抽象。
MEDIUM —— 性能
命令文档列出:非惯用代码模式、导出符号缺少 godoc 注释、低效字符串拼接、slice 未预分配、未使用表驱动测试。
代理补充的性能维度:
- 循环内字符串拼接:应使用
strings.Builder; - 缺少 slice 预分配:应使用
make([]T, 0, cap); - N+1 查询:循环内执行数据库查询;
- 热路径上不必要的分配。
MEDIUM —— 最佳实践
- Context 置首:
ctx context.Context应作为第一个参数; - 表驱动测试:测试应使用 table-driven 模式;
- 错误消息规范:小写字母开头、句末不带标点;
- 包命名规范:简短、全小写、不带下划线;
- 循环内 defer:存在资源累积风险。
自动化检查工具链
命令在执行审查时会运行以下 Go 工具链(命令文档原文,注释为补充说明):
# 静态分析:vet 随 Go 工具链分发,必选 go vet ./... # 高级检查(如已安装): staticcheck ./... golangci-lint run # 竞态检测:-race 要求 CGO 环境下构建,用于竞态检测 go build -race ./... # 安全漏洞扫描:官方漏洞库检查(需要 Go 1.18+ 的 toolchain 支持) govulncheck ./...go-reviewer 代理的诊断命令清单还补充了go test -race ./...(带竞态检测的测试运行),让静态分析与运行时验证形成闭环。
关于 golangci-lint 的推荐配置,skills/golang-patterns/SKILL.md 给出了可直接落地的.golangci.yml示例,其中启用了errcheck、gosimple、govet、ineffassign、staticcheck、unused、gofmt、goimports、misspell、unconvert、unparam等 linter,并对errcheck开启check-type-assertions: true、对govet开启shadow检查,可作为审查流水线的本地补充:
linters: enable: - errcheck - gosimple - govet - ineffassign - staticcheck - unused - gofmt - goimports - misspell - unconvert - unparam linters-settings: errcheck: check-type-assertions: true govet: enable: - shadow issues: exclude-use-default: false实战:审查报告的结构化解读
命令文档提供了一个完整的示例报告,直观展示了审查结果如何组织。核心结构包括:审查文件清单、静态分析结果、按严重级别排列的问题(每个问题附文件位置、问题描述、反例代码与修复代码)、以及汇总统计与合并建议:
User: /go-review Agent: # Go 代码审查报告 ## 审查的文件 - internal/handler/user.go (已修改) - internal/service/auth.go (已修改) ## 静态分析结果 ✓ go vet: 无问题 ✓ staticcheck: 无问题 ## 发现的问题 [CRITICAL] 竞态条件 文件: internal/service/auth.go:45 问题: 无同步地访问共享 map var cache = map[string]*Session{} // 并发访问! func GetSession(id string) *Session { return cache[id] // 竞态条件 } 修复: 使用 sync.RWMutex 或 sync.Map var ( cache = map[string]*Session{} cacheMu sync.RWMutex ) func GetSession(id string) *Session { cacheMu.RLock() defer cacheMu.RUnlock() return cache[id] } [HIGH] 缺少错误上下文 文件: internal/handler/user.go:28 问题: 未携带上下文地返回错误 return err // 无上下文 修复: 使用 %w 包装上下文 return fmt.Errorf("get user %s: %w", userID, err) ## 汇总 - CRITICAL: 1 - HIGH: 1 - MEDIUM: 0 建议: FAIL: 在 CRITICAL 问题修复前阻止合并示例背后的原理深化
竞态条件示例:
map[string]*Session{}是典型的共享可变状态,多个 goroutine 并发读写即构成数据竞争。修复方案sync.RWMutex提供了读多写少场景下的并行读能力;sync.Map则适合"写一次、读多次"的缓存场景。skills/golang-patterns/SKILL.md 同时强调:让零值可用(如sync.Mutex的零值即可直接使用)是 Go 类型设计的核心原则,这与审查时判断 mutex 是否被正确初始化直接相关。错误包装示例:
fmt.Errorf("get user %s: %w", userID, err)使用%w动词保留错误链,下游可通过errors.Is/errors.As解包。这与 rules/golang/coding-style.md 中"始终用上下文包装错误"的规则一致:
if err != nil { return fmt.Errorf("failed to create user: %w", err) }skills/golang-patterns/SKILL.md 还给出了配套的错误解包范式——用errors.Is(err, sql.ErrNoRows)判定哨兵错误、用errors.As(err, &validationErr)提取自定义错误类型,并强调"永远不要忽略错误",即便忽略也必须有明确注释说明为何安全(如_ = writer.Close()这类 best-effort 清理)。
批准标准与合并门禁
命令文档给出的审批判定表如下:
| 状态 | 条件 |
|---|---|
| PASS: 批准 | 无 CRITICAL 或 HIGH 问题 |
| WARNING: 警告 | 仅存在 MEDIUM 问题(谨慎合并) |
| FAIL: 阻止 | 发现 CRITICAL 或 HIGH 问题 |
这套标准与 go-reviewer 代理的Approve / Warning / Block判定逻辑完全一致。实际含义是:MEDIUM 级别的问题(如未预分配 slice、缺少 godoc 注释)不阻塞合并,但会被记录在报告中;而任何 CRITICAL(安全漏洞、竞态、goroutine 泄漏、硬编码凭证等)或 HIGH(错误链断裂、panic 误用、context 未传播等)问题都会直接阻断合并流程,直到修复并复查通过。
底层实现:go-reviewer 代理的工作机制
/go-review之所以能稳定输出符合上述格式的报告,关键在于 agents/go-reviewer.md 中的代理定义。它具备几个可考的实现细节:
- 工具权限:声明
tools: Read, Grep, Glob, Bash,即通过 Bash 运行 git/Go 工具链、通过 Read/Grep/Glob 读取源码上下文; - 模型选择:声明
model: sonnet,即由较快的推理模型承担审查任务; - Prompt Defense Baseline:代理内置了提示词防御基线——拒绝角色越权、拒绝泄露密钥与凭据、对 Unicode 同形字/零宽字符/编码伪装等注入手段保持警惕、将第三方/外部/抓取到的数据视为不可信内容并在行动前校验——这些约束保证了审查报告本身不被恶意提交的代码内容所劫持;
- 审查优先级:代理按 CRITICAL(安全、错误处理)→ HIGH(并发、代码质量)→ MEDIUM(性能、最佳实践)的优先级组织检查清单,与命令文档的三级分类一一对应。
从源码结构看,可以推断/go-review命令遵循 ECC 中"命令 → 代理(Agent)→ 技能(Skill)→ 规则(Rule)"的层层委托架构:命令文档负责触发入口,代理负责审查执行,golang-patterns与golang-testing技能负责提供模式知识,rules/golang/下的规则(见 rules/golang/coding-style.md、rules/golang/patterns.md、rules/golang/security.md、rules/golang/testing.md)则在开发阶段持续约束代码风格。
与审查相关的模式与测试知识库
审查的"尺度"由 ECC 内置的 Go 技能库提供,它们同时服务于代码编写与审查两个方向:
- skills/golang-patterns/SKILL.md:涵盖简洁性优先、零值可用、接受接口返回结构体、错误包装与自定义错误类型、Worker Pool、context 取消与超时、优雅停机、errgroup 协调、goroutine 泄漏规避、小型接口设计、函数式选项(Functional Options)、slice 预分配、
strings.Builder、sync.Pool等模式——审查中的 MEDIUM/性能类问题大多以此为依据; - skills/golang-testing/SKILL.md:涵盖 RED-GREEN-REFACTOR 的 TDD 流程、表驱动测试(含错误用例表)、子测试与并行子测试、
t.Helper()/t.Cleanup()/t.TempDir()、Golden Files、基于接口的 Mock、基准测试、模糊测试(Go 1.18+)、覆盖率与 CI 集成——审查中"未使用表驱动测试""缺少错误路径测试"等问题的判定标准即源于此。
例如,审查报告若标记"Slice not preallocated",对应技能中的修复范式为:
// Bad: 多次扩容 var results []Result for _, item := range items { results = append(results, process(item)) } // Good: 单次分配 results := make([]Result, 0, len(items)) for _, item := range items { results = append(results, process(item)) }与其他命令的集成工作流
命令文档明确给出了审查在整体开发流程中的位置:
- 先使用
/go-test确保测试通过(对应 commands/go-test.md 与 commands/go-test.md 提及的测试命令); - 构建出错时使用
/go-build; - 提交前使用
/go-review; - 非 Go 特有的问题(架构、通用设计等)使用
/code-review。
推荐的提交前组合拳为:go-test(验证行为正确)→ go build -race(验证并发安全)→ go-review(静态分析 + 安全 + 惯用性审查)→ 依据批准标准决定合并与否。这套流程将运行时验证与静态审查分层,避免把并发问题拖到 CI 或生产环境才暴露。
相关资源索引
- 命令文档(本主题):commands/go-review.md、docs/ja-JP/commands/go-review.md
- 代理定义:agents/go-reviewer.md
- 模式与测试技能:skills/golang-patterns/SKILL.md、skills/golang-testing/SKILL.md
- 语言规则:rules/golang/coding-style.md、rules/golang/patterns.md、rules/golang/security.md、rules/golang/testing.md
- 相关命令:commands/go-test.md、commands/code-review.md
掌握/go-review的使用,等于把资深 Go 审查者的检查清单、工具链与合并门禁固化到了每次提交之前——它既是代码质量守门员,也是学习惯用 Go 的即时反馈教练。
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考