登录/注册
代码扫描 | 把控代码质量的利器

初见代码扫描

有位小伙子在办公大楼门口抽烟,一位路人经过他的身边对他说:“你知不知道这个东西会危害你的健康?你有没有注意到香烟盒上的那个警告(Warning)?”
小伙子说:“没事儿,我是一个程序员。”
路人说:“这又怎样?”
程序员回答道:“我们从来不关心 Warning,只关心 Error。”

以笑开场,这是一篇写给极少使用/了解代码扫描工具的用户的“启蒙”读物。一方面因为代码扫描存在一定的技术壁垒,涉及到词法/语法分析、编译注入、模式识别及安全等相关领域,想要了解这方面的内容可能难以下手;另一方面,由于目前大众对于代码扫描产品及其领域还存在着较多误解,极大程度上影响了代码扫描的使用体验,更有甚者直接把 Lint/Style 与扫描划了等号,让人啼笑皆非。

CODING 代码扫描自开放试用以来,已累计为 5000+ 团队提供扫描服务,帮助开发团队及时发现了大量潜藏的代码缺陷、安全漏洞以及不规范代码。希望通过这篇文章,以一些常见场景为例,通俗易懂地解释代码扫描的价值与使用方法,帮助读者深入理解,快速上手,让代码扫描产品在助力企业建设 DevSecOps 的道路上,发挥最大的价值。

代码扫描有什么价值

抛开那些老生常谈的 质量前移质量内建 的概念,从实际运用的角度来看,代码扫描往往是一个团队向 DevOps 转型的第二步(第一步是持续集成/流水线)。一是因为流水线上只跑了编译打包部署还是略显单薄,二是相比单侧、接口自动化及 e2e 自动化,接入代码扫描的成本是最低的。以 Jenkins 为例,只需要运维在 Jenkins 集群中安装 SonarQube 插件,再在 Jenkinsfile 中增加一行命令,就可以在无需开发人员介入的前提下,完成代码扫描的接入。

在 Jenkins 里启用 Sonar

此外,稍有代码文化意识的开发也会在本地 IDE 中安装插件做本地检查,一旦出现语法或者风格问题时能直接在 IDE 上标注警示甚至自动修复。

VSCode lint 检查

越容易得到的东西往往也最容易被忽视,IDE 的 auto inspect/format 或流水线的静默执行,容易让研发淡化代码扫描的感知和价值:我有做 Style check,完成了代码检查任务研发上线周期太紧张,扫描的问题以后再看代码扫描发现的问题无伤大雅代码扫描这个工具/环节可有可无。事实上,各大软件/互联网厂商每年都会花费上百万购买各类扫描软件 License(SonarQube、Coverity、Checkmarx 等),而这些公司也均为估值十多亿的行业佼佼者(16 年 Sonar 获 4500 万美金融资,14 年 Coverity 以 3.75 亿被收购)。巨大的市场价值和卑微的存在感,为什么会出现这样的现象?要弄清楚这个问题,首先看看代码扫描能帮助我们发现哪些问题。

0. 编程语法问题

之所以列为第 0 项,是因为我认为这个问题甚至不属于代码扫描的范畴。目前有非常多的 IDE 和插件集成了语法检查相关的功能,帮助开发在研发过程中检查、提示甚至是自动修复语法问题,解决了一些代码质量上的问题,但这是语法解析器的职责,与代码扫描关系甚微。

语法检查

1. 代码规范问题

很多读者看到这可能会露出“我又懂了”的表情,这是目前代码扫描给大家留下的最普遍的感知:检查有没有注释缩进是空格还是 Tab大括号是另起一行还是接着上一行等等。诸如此类的检查标准很容易在团队中引发论战,同时因为这类问题也并不阻碍功能逻辑的正确运行(不关心 Warning,只关心 Error),所以很多人对代码扫描的尝试就到这里了。

然而,代码规范真的无足轻重吗?

如果此处没有特别提醒,你能意识到动态语言中返回值不一致,后面可能存在什么困扰么?

不一致的返回值

如果此处没有特别提醒,你能意识到入参这里为可变对象,可能会引入什么问题么?

危险的默认值

如果继续放任 for、if、try 的嵌套,之后这部分代码该如何读?

代码复杂度

后续变更模型字段后,还能记得需要修改多处相同代码吗?

重复代码

代码规范类的扫描就是为了解决 “在代码里下毒” 的最有效手段。同时针对多人合作项目,如果要避免 “当我写这个代码时,只有我和上帝知道是什么意思;一个月后,只有上帝知道” 的场景,遵循统一的代码规范也是非常必要的。

2. 功能缺陷

很多人抱有侥幸心理: “我的代码可能就这一个版本,以后不需要再维护,所以能跑就 OK 了”。 那么让代码扫描来帮助确认一下,你的代码真的能跑吗?

这些空指针问题,你确定都能测试出来?

空指针

数组越界的问题,通过人肉 CR 发现的难度有多大?

数组越界

更别提这种内存泄漏问题,没有工具帮助人肉定位,管理内存还是需要一些功夫。

内存泄漏

从这个角度来看,代码扫描等同于测试环节,是保障应用功能正常的有效手段,也能更高效地发掘出更有深度的技术问题。

3. 安全缺陷

可能有的读者还会觉得 “我的功能很简单,点几下就测试通过了,没什么别的问题”。要知道一个应用程序除了要从功能上满足用户,还需要盯防虎视眈眈的黑产, 万豪泄露用户数据遭受重罚 类似的案件历历在目,我们有多大的把握能保证不是下一个目标?

拖库很重要的一个切入点就是 SQL 注入,而这类问题用代码扫描工具可以很容易发现。

SQL 注入

远程命令执行也是攻克目标机器的常用手段,许多常用的开源组件都被爆出过类似问题,你确定你的安全意识比 Apache 还要好吗?

远程命令执行

还有 CSRF、XSS、XXE、反序列化等多重攻击手段,如果每个一线程序员都需要对这些了如指掌小心避让,那管控成本将直线上升。通过代码扫描快速查找与定位风险,可以以最低成本为数字资产保驾护航。静态代码分析(SAST)也是 DevSevOps 里最基础、最低门槛的检测方式之一。

4. 公关风险

“别逗了,聊代码质量怎么还能聊出公关问题”, 先别笑,让我们看一则新闻:vivo 的升降摄像头:流氓软件检测器还是智商鉴定器?

简单来说,Android 应用程序在获取摄像头参数时,调用的函数可能会触发摄像头的升起,但实际上看客并不会深究这里的技术实现细节。打开了摄像头,就是想偷拍用户,这在当时是一场不折不扣的公关危机,还掀起了不小的风波,波及到了各方。在对外科普辟谣的同时,腾讯内部也组织出了一套敏感 API 扫描方案,通过代码扫描工具来扫描项目中的敏感接口,提醒开发人员自查确认,防止造成更大的风险。

敏感 API 扫描

代码扫描应该怎么用

通过上文,大家可能逐步意识到了代码扫描为团队带来的价值: 以低门槛无侵入的方式保障代码质量和安全,那么就去下载了 SonarQube、Spotbugs、Checkstyle 等工具,简单配置后便在本地或 Jenkins 流水线上跑起来了。但既然代码扫描更偏向于本地离线的工具,CODING 为什么要在线上平台提供代码扫描呢?

本地扫描,规则与远端同步

即便是本地扫描,我们也不希望本地规则和远端的规则有差异,导致本地扫描通过提交后又被驳回。解决这个问题最合理的方式是 IaC,即扫描方案和过滤条件等都以本地配置文件的方式去保存。

eslint 本地配置

但并不是所有工具的规则配置都可以本地化管理,例如过滤条件、对比分支等和应用场景强相关的配置项。针对这类诉求,应对的思路有两种:

  1. 用户在平台侧完成统一的配置(包括工具规则、过滤条件、对比分支等),配置完成后生成配置 ID。本地扫描时不再基于本地配置文件,而是基于远端的配置 ID。
    1
    codedog_client localscan --config 001
  2. 平台配置的本地化,即扫描平台定义完整的规则格式。不仅本地扫描时遵循此配置,在平台展示时也能解析文件配置生成可视化展示,从而达到统一的 IaC 配置

细化到人,把问题转为责任

本地扫描可以发现问题,但是难以发现此问题的引入人和引入时机,因此这些问题要不要改、谁来改,存在着纠缠和推诿的可能。而平台可以基于代码的提交记录,追溯到代码的变更时机,发现问题责任人,从而以责任人为视图进行问题跟踪,甚至可以转成 Bug 专项跟进。谁污染谁治理,这很合理。

问题责任人

此外,平台还可以根据下一次扫描的结果,自动关闭当前已经修复的代码问题,节省人工操作。

代码库质量追踪

把问题放在平台归档还有一个好处,就是可以很清晰的知道某个仓库的代码质量趋势,例如在某个时间点引入了新问题导致整体质量变差,或是在某个时间点解除历史负载质量提升。可视化的质量波动趋势图也可以帮助团队管理者更直观的判断,当前是否需要为团队的代码质量敲敲警钟。

代码质量趋势

质量门禁,既往不咎来者可追

只是做本地扫描,还是会有“心大”的开发者不修复问题直接 push 到远端,这时就可以通过平台侧提供的质量门禁功能来做拦截了。质量门禁可以定义当前仓库可以允许的问题数量,当超出问题数量,这次提交或者合并请求将被拦截。

扫描门禁

合并请求中的代码质量门禁

通常,历史项目在接入扫描时会一次性扫出成百上千个遗留问题,而团队也不太可能专门预留时间一次性根治,导致“刚入门就劝退”。针对这类场景我们的建议是,设置 MR 的质量门禁为新增问题数,保证在代码合入时不会有新代码质量问题引入,控制增量的同时再逐步清理存量问题(业务需求会改到哪个文件,就修复这个文件的代码质量问题),通过这种方式慢慢将代码质量拉回正轨。

总结

某种程度上我们认可越大规模的团队越需要代码扫描工具,来帮助团队提升面对规范和复杂问题的标准和效率。针对 SMB 和个人开发者,代码扫描也依然是接入成本最低的质量提升工具。希望通过以上案例和场景,能帮助各位读者快速定位项目中的卡点并顺利解决,关注每行代码迭代,传承卓越代码文化。

注册即用,体验酣畅的开发流程

立即使用