L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Données et recherche · SKILL.md

golang-code-review

golang-code-review

对 Golang 项目进行代码安全评审。触发场景:用户想评审 Go 代码改动、检查 PR/MR 安全问题、review golang 代码、分析 gorm SQL 改动、检查 panic/error/越界风险。工作流:基于 git diff(当前分支 vs master)获取改动代码,结合上下文分析安全隐患,并列出所有 GORM SQL 改动及其原始 SQL。只要用户提到"review golang"、"评审 go 代码"、"检查 go 改动"、"gorm sql 分析"等,必须触发本 skill。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: golang-code-review
description: >
对 Golang 项目进行代码安全评审。触发场景:用户想评审 Go 代码改动、检查 PR/MR 安全问题、review golang 代码、分析 gorm SQL 改动、检查 panic/error/越界风险。工作流:基于 git diff(当前分支 vs master)获取改动代码,结合上下文分析安全隐患,并列出所有 GORM SQL 改动及其原始 SQL。只要用户提到"review golang"、"评审 go 代码"、"检查 go 改动"、"gorm sql 分析"等,必须触发本 skill。


Golang Code Review Skill

概述

本 skill 用于对 Golang 项目做安全评审,聚焦以下三类问题:

  1. 安全风险:panic、未判断 error、数组越界、nil 指针解引用
  2. GORM SQL 改动:提取所有使用 GORM 框架的 SQL 操作,还原原始 SQL 语句

执行步骤

Step 1:分支来源检查

在做代码评审之前,先验证当前分支的来源是否符合规范。

# 获取当前分支名
git branch --show-current

# 检查当前分支是否从 master 切出(找到与 master 的分叉点)
git merge-base HEAD master

# 查看从分叉点到现在的所有 merge commit,检查是否有 develop 分支合入
git log $(git merge-base HEAD master)..HEAD --merges --oneline

# 查看完整提交历史(含合并),找出所有合入的分支名
git log $(git merge-base HEAD master)..HEAD --oneline --graph

判断逻辑:

  1. 验证是否从 master 切出
# 找分叉点
FORK_POINT=$(git merge-base HEAD master)
# 检查分叉点是否在 master 的提交历史中
git branch --contains $FORK_POINT | grep -E '^\*?\s*master#x27;
- ✅ 分叉点存在于 master 历史 → 分支来源正常
- ❌ 分叉点不在 master 历史 → 说明不是从 master 切出,输出警告

2. 检查是否有 develop 分支代码合入

# 查找 merge commit 中来自 develop 的记录
git log $(git merge-base HEAD master)..HEAD --merges --oneline | grep -i develop

# 或通过引用日志确认
git log $(git merge-base HEAD master)..HEAD --oneline --graph | grep -i develop
- ✅ 无 develop 相关 merge commit → 分支干净
- ❌ 发现 develop 分支合入记录 → 输出高危警告,列出具体 merge commit

输出格式(在最终报告最前面展示):

【分支来源检查】
当前分支: feature/xxx
分叉自:   master (commit: a1b2c3d)

✅ 来源正常:当前分支从 master 切出
❌ 警告:检测到 develop 分支代码合入!
   Merge commit: f3e2d1c  Merge branch 'develop' into feature/xxx
   合入时间: 2024-01-15 14:32
   风险说明: develop 分支可能包含未经测试或未上线的功能,混入当前分支可能导致意外代码上线

如果 develop 分支有代码合入,应在评审报告顶部用 🔴 标注,提醒评审人重点关注。

Step 2:获取 Git Diff

# 获取当前分支与 master 的完整 diff(含上下文行)
git diff master...HEAD -- '*.go'

# 如果 master 不存在,尝试 main
git diff main...HEAD -- '*.go'

# 获取变更的文件列表
git diff --name-only master...HEAD -- '*.go'

如果仓库没有 master/main,改用:

git log --oneline -1  # 确认 HEAD
git diff HEAD~1 HEAD -- '*.go'

Step 3:获取上下文代码

对于 diff 中涉及的每个文件,获取完整文件内容以理解上下文:

# 获取变更文件的完整内容(当前版本)
git show HEAD:<filepath>

# 或直接读取工作区文件
cat <filepath>

重点关注:

  • diff 所在函数的完整实现
  • 被修改代码调用的函数签名
  • 结构体定义(判断字段是否可为 nil)
  • 错误处理链路

读取文件时使用带行号的命令,为后续行号定位做准备:

# 带行号读取,方便后续 grep 验证
cat -n <filepath>

# 或只看关键函数所在区域
grep -n "func \|\.Where\|\.Find\|\.Create\|\.Update\|\.Delete" <filepath>

Step 4:安全问题分析

逐一检查以下风险类别:

3.1 Panic 风险

场景检查点
nil 指针解引用指针/接口在使用前是否判空
类型断言x.(T) 是否使用双返回值 v, ok := x.(T)
map 并发读写是否有并发场景未加锁
channel 操作向关闭的 channel 发送数据
空接口转换interface{} 断言未处理 ok

3.2 未判断 Error

场景检查点
函数返回 error_, err 中 err 是否被 if err != nil 检查
GORM 操作.Error 字段是否被检查
文件操作os.Open/Read/Write 的 error
JSON 解析json.Unmarshal 的 error
类型转换strconv 系列函数的 error

3.3 数组/切片越界

场景检查点
直接下标访问arr[i] 前是否判断 i < len(arr)
切片操作s[a:b] 中 b 是否可能超出 len
空切片取第一个s[0] 前是否判断 len(s) > 0
for range 后取值循环结束后直接取值可能越界

4.4 其他常见问题

  • goroutine 泄露(context 未传递或未取消)
  • 锁未释放(defer mu.Unlock() 是否正确)
  • 资源未关闭(rows.Close()、file.Close())

Step 5:提取 GORM SQL 改动

识别所有 GORM 操作并还原原始 SQL。

5.1 识别 GORM 操作模式

// 查询类
db.Where(...).Find(&result)
db.Where(...).First(&result)
db.Raw("SELECT ...").Scan(&result)
db.Table("...").Select("...").Where(...).Find(...)

// 写入类
db.Create(&obj)
db.Save(&obj)
db.Model(&obj).Update(field, value)
db.Model(&obj).Updates(map/struct)

// 删除类
db.Where(...).Delete(&obj)
db.Unscoped().Where(...).Delete(&obj)

// 执行类
db.Exec("UPDATE ...")

5.2 SQL 还原规则

GORM 代码对应 SQL
.Where("name = ?", "tom")WHERE name = 'tom'
.Where("age > ? AND status = ?", 18, 1)WHERE age > 18 AND status = 1
.Where(User{Name: "tom"})WHERE name = 'tom'
.Find(&users)SELECT * FROM users
.Select("id, name")SELECT id, name FROM ...
.Limit(10).Offset(20)LIMIT 10 OFFSET 20
.Order("created_at DESC")ORDER BY created_at DESC
.Joins("LEFT JOIN orders ON ...")LEFT JOIN orders ON ...
.Create(&user)INSERT INTO users (...) VALUES (...)
.Save(&user)INSERT ... ON DUPLICATE KEY UPDATE 或 UPDATE users SET ... WHERE id=?
.Updates(map)UPDATE users SET col1=?, col2=? WHERE ...
.Delete(&user)DELETE FROM users WHERE id=?(软删除:UPDATE users SET deleted_at=? WHERE id=?)
.Unscoped().Delete()DELETE FROM users WHERE id=?(硬删除)

还原步骤:

  1. 确定操作表名(Model/Table 参数或结构体名转 snake_case)
  2. 拼接 SELECT 子句
  3. 拼接 JOIN 子句
  4. 拼接 WHERE 条件,将 ? 替换为实际值(如能推断)
  5. 拼接 ORDER BY / LIMIT / OFFSET
  6. 对写操作,列出所有被修改的字段

行号确认(重要)

git diff 输出的 @@ 行号是 diff 上下文行号,不能直接用于报告,必须通过当前分支的实际文件确认真实行号。

对每一处需要标注行号的问题代码,执行以下步骤:

# 用问题代码的关键字在当前文件中定位真实行号
grep -n "关键代码片段" <filepath>

# 如果关键字不唯一,结合函数名缩小范围
grep -n "func FunctionName" <filepath>

# 多行 GORM 链式调用,用链式起始行定位
grep -n "db\.Where\|db\.Model\|db\.Table" <filepath>

规则:

  • 报告中的行号必须来自 grep -n 的实际输出,不得使用 diff 中的 @@ 行号
  • 对于多行链式调用(如 GORM),行号指向该调用的第一行
  • 若同一代码片段出现多次,结合函数上下文取正确的那一处

输出格式

一、安全风险清单

按严重程度排列(🔴 高危 / 🟡 中危 / 🟢 低危):

🔴 [高危] 文件: internal/service/user.go, 行: 42
   问题: nil 指针解引用 —— user 可能为 nil,但直接访问 user.Name
   改动前: (原始代码)
   改动后: (新代码)
   建议: 在使用 user 前添加 if user == nil { return ... }

🟡 [中危] 文件: internal/repo/order.go, 行: 88
   问题: GORM 查询结果未判断 Error
   改动后: result := db.Where(...).Find(&orders)
   建议: 添加 if result.Error != nil { return result.Error }

二、GORM SQL 改动清单

【新增】internal/repo/order.go, 行: 55
GORM 代码:
  db.Where("user_id = ? AND status IN ?", userID, []int{1, 2}).
     Order("created_at DESC").
     Limit(10).
     Find(&orders)

原始 SQL:
  SELECT * FROM orders
  WHERE user_id = <userID> AND status IN (1, 2)
  ORDER BY created_at DESC
  LIMIT 10

备注: 如 Order 有 deleted_at 字段(软删除),实际 SQL 还会附加 AND deleted_at IS NULL

---

【修改】internal/repo/product.go, 行: 120
GORM 代码(改动前):
  db.Where("id = ?", id).First(&product)

GORM 代码(改动后):
  db.Where("id = ? AND shop_id = ?", id, shopID).First(&product)

原始 SQL(改动后):
  SELECT * FROM products
  WHERE id = <id> AND shop_id = <shopID>
  ORDER BY id
  LIMIT 1

注意事项

  • 若项目使用了 GORM v1(github.com/jinzhu/gorm)和 v2(gorm.io/gorm),软删除行为略有差异,请在备注中注明版本
  • 对于 db.Raw() 和 db.Exec(),直接提取 SQL 字符串,无需转换
  • 链式调用跨多行时,需完整拼接所有条件
  • Scopes 函数(db.Scopes(ActiveUser))需追踪 Scope 定义来还原条件
Skills enregistrées