静态代码分析(SAST)入门:什么是SAST、常见工具、在CI/CD中集成SAST
聊到代码质量,我第一个想到的就是静态代码分析。说白了,SAST 就是在不运行代码的情况下,直接扫描你的源代码,找出潜在的问题。你想想看,代码还没跑起来,就能发现一堆坑,这多省事。
我记得刚入行那会儿,团队里有个老哥,每次提交代码都特别自信。结果上线后,空指针异常、SQL 注入漏洞轮着来。后来我们上了 SAST,他的代码在 CI 阶段就被拦下来了。嗯,从那以后,他再也不敢裸写代码了。
什么是 SAST?
SAST 全称是 Static Application Security Testing,中文叫静态应用安全测试。它像是一个严格的代码审查员,逐行扫描你的代码,检查有没有安全漏洞、代码坏味道、不符合规范的地方。
它的工作原理其实不复杂:
- 先把你的代码解析成抽象语法树(AST)
- 然后根据预定义的规则集,在树上做模式匹配
- 最后把匹配到的问题汇总成报告
我在项目中遇到过最典型的例子,就是有人把数据库密码硬编码在代码里。SAST 一扫描,直接标红。这种问题如果等到上线再发现,后果你懂的。
核心要点:SAST 是在开发阶段就介入的,越早发现问题,修复成本越低。这跟体检一个道理,小病不治,大病难医。
常见工具:SonarQube、ESLint、Pylint
工具这东西,选对了事半功倍。我这些年用过不少,挑三个最常用的说说。
SonarQube
SonarQube 算是 SAST 领域的老大哥了。它支持 30 多种语言,从 Java、Python 到 JavaScript 都能管。我最喜欢它的质量门(Quality Gate)功能——代码质量不达标,直接不让合并。
它的工作流程大概是这样的:
- 开发者提交代码
- SonarQube 扫描分析
- 生成报告,给出质量评分
- 如果评分低于阈值,CI 流程直接失败
我曾经在一个遗留项目上用过 SonarQube,第一次扫描结果惨不忍睹——技术债务累计了 300 多天。我们花了两个月逐步修复,最后质量评分从 D 提到了 A。那种成就感,真的爽。
ESLint
如果你写 JavaScript 或 TypeScript,ESLint 几乎是标配。它不光检查语法错误,还能统一代码风格。团队里有人喜欢用分号,有人不喜欢?ESLint 直接帮你搞定。
一个简单的配置示例:
// .eslintrc.json
{
"rules": {
"no-unused-vars": "error",
"no-console": "warn",
"eqeqeq": ["error", "always"]
}
}
我个人习惯把 ESLint 配置得严格一点。比如 no-unused-vars 设成 error,未使用的变量直接报错。这样能逼着开发者清理无用代码,减少维护成本。
小技巧:ESLint 可以配合 Prettier 一起用。ESLint 管逻辑问题,Prettier 管格式问题,各司其职。
Pylint
Python 项目的话,Pylint 是首选。它检查的东西很细,从命名规范到代码复杂度,都能覆盖到。
举个例子:
# 不好的写法
def f(x, y):
if x > 0:
return x + y
else:
return x - y
# Pylint 会提示:函数名太短,不符合命名规范
# 建议改成:def calculate_result(x, y):
我记得有一次,团队里新来的同事写了个函数,嵌套了 8 层 if-else。Pylint 直接给了个复杂度警告。我们重构后,代码可读性提升了一大截。
| 工具 | 适用语言 | 主要功能 | 我的评价 |
|---|---|---|---|
| SonarQube | 多语言(30+) | 质量门、技术债务管理 | 企业级首选,功能全面 |
| ESLint | JavaScript/TypeScript | 代码规范、错误检查 | 前端必备,配置灵活 |
| Pylint | Python | 命名规范、复杂度检查 | Python 项目标配 |
在 CI/CD 中集成 SAST
光有工具不行,得把它集成到流水线里,才能发挥最大价值。我见过太多团队,SAST 工具装好了,但没人用,最后成了摆设。
集成 SAST 的核心思路就一句话:让扫描成为 CI/CD 流程的必经关卡。
以 GitLab CI 为例,一个简单的集成配置:
# .gitlab-ci.yml
stages:
- test
sast:
stage: test
script:
- sonar-scanner
only:
- merge_requests
allow_failure: false
这里的关键点是 allow_failure: false。意思是 SAST 扫描不通过,流水线直接失败。这样能确保每个合并请求都经过质量检查。
避坑指南:我曾经把 SAST 扫描放在代码提交后立即执行,结果发现扫描时间太长,开发者等得心烦。后来我改成在合并请求阶段触发,既保证了质量,又不影响日常开发节奏。
集成时要注意几个点:
- 扫描时机:建议在合并请求阶段触发,而不是每次提交都跑
- 阈值设置:刚开始别设太严,先收集数据,再逐步收紧
- 结果反馈:扫描结果要能直接关联到代码行,方便开发者定位问题
我现在的做法是,在 CI 流水线里加一个 SAST 阶段,扫描结果直接显示在合并请求的评论区。开发者打开 MR,就能看到哪些代码有问题,哪里需要改。这样效率高很多。
总结一下:SAST 不是银弹,但它能帮你拦住 80% 的常见问题。配合 CI/CD 使用,效果翻倍。别等到上线了才发现问题,那时候改起来就痛苦了。
好了,这一章就聊到这儿。下一章我们讲讲动态分析,那又是另一个有意思的话题了。