为您的 Python 应用程序交付干净安全的代码
简介
如今的开发人员肩负重任——他们不仅要解决行业中一些最大的挑战,而且还必须从一开始就以最高的代码质量和安全标准交付这些解决方案。
这里重点介绍的成功案例展示了为什么静态代码分析工具对于改进代码质量和代码安全至关重要,以及它们如何帮助 Python 社区识别(并修复)一些著名的开源 Python 项目中的错误和漏洞。
不断增长的技术债务和安全担忧
随着 Python 应用程序在新颖的用例中快速增长,开发团队面临着越来越大的压力,需要按时完成项目并按计划交付项目——通常,代码可靠性、可维护性和安全性被置于次要地位。这样做不仅会累积长期的技术债务,还可能在代码库中留下巨大的安全漏洞。
为了尽早发现开发过程中的问题(左移方法),团队通常对新的和高级的工具感兴趣,以查看它们是否适合其工作流程,是否足够直观,以及是否可以帮助他们实现此目标。值得庆幸的是,有许多工具和工作流程可以帮助 Python 用户。事实上,Python 生态系统拥有丰富的 linting 和静态分析工具(例如 PyLint、Flake8、Bandit、PyT、PySa 等等),并且大多数 Python 开发人员已经在使用其中一个或多个工具。
在 SonarSource,我们非常熟悉开发社区的需求(和痛点)。事实上,我们认为只有开发人员才能对代码质量和代码安全产生可持续的影响。这就是为什么我们构建开源和商业代码分析器——SonarLint、SonarCloud、SonarQube,其使命是使团队能够在他们现有的工作流程中解决编码问题。在这一使命中,我们同样肩负着巨大的责任,这意味着提供精确且可操作的反馈,并以高精度(即最大限度地减少误报)发现问题。
在下一节中,我们将讨论分析流行的开源 Python 项目如何不仅为贡献者提供出色的反馈,还有助于不断提高静态代码分析工具的质量和精度——一个协作的、社区驱动的循环。
在流行的 Python 项目中发现的错误和漏洞
我们使用 SonarCloud 分析了一些开源项目 tensorflow、numpy、salt、sentry 和 biopython,以识别任何巨大的漏洞。我们知道这些高可见性的开源项目经常被数千个项目使用,并且它们的开发工作流程包括所有最佳实践——代码审查、测试覆盖率、使用多种工具(flake8、pylint、Bandit 等)。我们使用 SonarCloud 分析了这些项目,结果非常有趣。不用说,这些问题很快就被这些项目承认并修复了。
“SonarCloud 发现的一些东西令人印象深刻(可能是由一些自省和/或类型推断驱动的),而不仅仅是我在大多数 flake8 生态系统中习惯的简单模式匹配。”
--- Peter J. A. Cock - BioPython 的维护者(此处为原始帖子)
下面重点介绍了分析的一些项目示例以及其他工具遗漏但由 SonarCloud 标记的问题。当您阅读这些内容时,不仅要考虑工具的功能,还要将其视为一个学习机会,以便在将来主动避免类似的陷阱。
类型错误
下面的示例显示了在 Tensorflow 上发现的问题——一个由 Google 开发的开源机器学习平台。
SonarCloud 具有类型推断引擎,使其能够检测高级类型错误。它使用它可以找到的所有信息来推断变量类型,包括 Typeshed 存根、赋值和您的类型注释。同时,如果您不使用类型注释,它也不会抱怨,并且它旨在避免误报。
这里的控制流分析使其能够理解 state_shape
是一个元组,因为当 output_shape
是一个 tuple
时,它被分配为 output_shape[1:]
。该算法能够忽略稍后对 output_shape
的 list
赋值。
无法访问的代码
下面的示例显示了在 Sentry 上发现的问题——一个 Python 性能和错误瓶颈监控库。
当死代码刚好在 return
或 raise
语句之后时,检测死代码很容易。当 return
是有条件的时,情况会稍微复杂一些。SonarCloud 使用控制流图来检测多个分支在到达语句之前退出的情况。
格式化字符串中的错误字段
下面的示例显示了在 Salt 项目上发现的问题——一个用于事件驱动自动化、远程任务执行和配置管理的 python 包。
在字符串格式化期间引用错误的字段名称或索引非常常见。Pylint 和 Flake8 具有使用字符串文字检测此问题的规则,但当格式字符串位于变量中时,它们会遗漏错误。
未引发的异常
下面的示例显示了在 Biopython 上发现的问题——一个用于生物计算和信息学的工具
当我们审查代码时,我们通常会查看类、变量和其他有意义的符号,并且经常忘记检查小细节,例如“我的异常之前是否有 raise 关键字”。SonarCloud 会分析整个项目以提取类型层次结构。它可以检测何时丢弃自定义异常,而不仅仅是内置异常。
没有意义的比较
下面的示例显示了在 Numpy 上发现的问题——一个用于大型多维数组和矩阵的数值计算库。SonarCloud 有许多规则可以检测没有意义的代码。使用 ==
比较不兼容的类型永远不会失败,但它始终会返回 False,如果您使用 !=
,则返回 True。在这里,我们可以看到一个问题,因为 platform.architecture()
返回一个元组。
这些只是几个示例,您可以在各个 github 项目上找到项目维护人员标记和修复的所有问题——tensorflow、numpy、salt、sentry 和 biopython。
在正确的时间和地点提供正确的指导
构建和维护优秀的软件涉及多个团队使用多个工具,并且重要的是为团队提供在正确的时间和地点提供正确指导的工具。
SonarLint、SonarQube 和 SonarCloud 可以通过以下方式帮助 Python 开发人员做好他们的工作:
- 从 IDE 开始,通过代码审查工作流程,一直到部署管道的自动化代码分析。
- 在开发周期的早期检测各种代码质量和代码安全问题。
- 帮助团队“像您编码一样清理”,从而使交付的新代码具有最高的质量和安全标准,并因此减少长期的技术债务。
为了在您在 IDE 中编写代码时快速检测问题,SonarLint(开源且完全免费)可从您选择的 IDE 市场获得 www.sonarlint.org/
SonarQube 和 SonarCloud 分别是本地和云解决方案,可帮助项目在您的代码存储库平台(例如 GitLab、GitHub、Azure DevOps 或 Bitbucket)中检测错误、漏洞、代码异味和安全热点,从而使团队只能合并高质量和安全的代码。它们对于任何开源项目都是完全免费的。您可以在 www.sonarqube.com 或 www.sonarcloud.com 试用。
如果您对 Python 代码存储库中可能隐藏的错误或漏洞感到好奇,那么就像我们以前的示例一样,立即分析您的项目。这是一个加强您的开发管道并尽早发现问题的绝佳机会。在此过程中,您也可能会发现这是一个很好的学习机会,并发现您可能没有意识到的最佳实践和/或危险模式。