为您的 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 Project 上发现的问题——一个用于事件驱动自动化、远程任务执行和配置管理的 Python 包。
在字符串格式化过程中,引用错误的字段名或索引是相当常见的。Pylint 和 Flake8 有规则可以检测字符串字面量中的这个问题,但当格式字符串位于变量中时,它们会漏掉这些缺陷。
未抛出的异常
下面的例子展示了在 Biopython 上发现的问题——一个用于生物计算和信息学的工具。
当我们审查代码时,通常会关注类、变量和其他有意义的符号,而常常忘记检查一些小细节,例如“我的异常前面是否有 raise 关键字”。SonarCloud 会分析整个项目以提取类型层次结构。它能检测到自定义异常被丢弃的情况,而不仅仅是内置异常。
无意义的比较
下面的例子展示了在 Numpy 上发现的问题——一个用于处理大型多维数组和矩阵的数值计算库。SonarCloud 有许多规则可以检测没有意义的代码。用 `==` 比较不兼容的类型永远不会失败,但它总是返回 False,如果使用 `!=` 则返回 True。在这里我们可以看到一个问题,因为 `platform.architecture()` 返回的是一个元组。
这些只是几个例子,您可以在各个 GitHub 项目上找到所有被项目维护者标记和修复的问题 – tensorflow、numpy、salt、sentry 和 biopython。
在正确的时间和地点提供正确的指导
构建和维护优秀的软件涉及多个团队使用多种工具,因此,为团队提供能够在正确的时间和地点提供正确指导的工具至关重要。
SonarLint、SonarQube 和 SonarCloud 可以通过以下方式帮助 Python 开发人员更好地完成工作:
- 从 IDE 开始,贯穿代码审查工作流程,直至部署流水线,实现自动化代码分析。
- 在开发周期的早期检测各种代码质量和代码安全问题。
- 帮助团队实现“编码即净化(Clean as you Code)”,从而使交付的新代码达到最高的质量和安全标准,并因此减少长期技术债。
要在您的 IDE 中边写代码边快速检测问题,可以从您选择的 IDE 市场下载 SonarLint(开源且完全免费):www.sonarlint.org/
SonarQube 和 SonarCloud 分别是本地部署和云端解决方案,它们帮助项目在代码仓库平台(如 GitLab、GitHub、Azure DevOps 或 Bitbucket)中检测缺陷、漏洞、代码异味和安全热点,使团队只合并高质量和安全的代码。它们对任何开源项目都是完全免费的。您可以在 www.sonarqube.com 或 www.sonarcloud.com 上试用。
如果您好奇您的 Python 代码仓库中可能隐藏着哪些缺陷或漏洞,那么就像我们在前面的例子中所做的那样,去分析您的项目吧。这是加强您的开发流程并在早期发现问题的绝佳机会。在这个过程中,您可能还会发现这是一个很好的学习机会,并了解到一些您可能不知道的最佳实践和/或危险模式。