pytest 6.2.3 发布解读:临时目录安全加固 Bugfix 版本的技术细节与升级指南
2026/9/15 17:05:00 网站建设 项目流程

pytest 6.2.3 发布解读:临时目录安全加固 Bugfix 版本的技术细节与升级指南

【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest

本文基于 pytest 仓库中的 release-6.2.3.rst 发布公告,结合 CHANGELOG 对应条目 及 src/_pytest/tmpdir.py 的源码实现,完整还原 pytest 6.2.3 作为 Bugfix 版本的全部修复内容、安全问题根因与修复机理,并给出可落地的升级与验证方案。读完本文,你将掌握:pytest 6.2.3 修复了什么安全漏洞、临时目录权限在源码层如何被收紧、如何快速验证自己的环境是否受影响,以及如何安全升级。

pytest 6.2.3 于 2021 年 4 月 3 日发布到 PyPI,是一个纯 Bugfix(bug-fix)版本,定位为可无缝替换的 drop-in replacement,不引入任何新功能、不破坏既有用法。它修复的安全问题聚焦于测试框架最常用的临时目录机制(tmp_path/tmpdirfixture)的权限缺陷。对于任何在多用户系统上运行 pytest 的团队,这个版本都值得立即关注。

一、发布背景与版本定位

根据 release-6.2.3.rst,本次发布的要点如下:

  • 版本性质:Bug-fix 版本,作为 drop-in replacement(即插即用替换),升级不需要修改任何测试代码或配置。
  • 升级方式pip install --upgrade pytest
  • 修复问题编号:GitHub Issue #8414。
  • 主要贡献者:Bruno Oliveira、Ran Benita。
  • 完整变更日志:官方 changelog(即仓库中的 doc/en/changelog.rst,对应条目在 6.2.3 段落)。

该公告本身言简意赅,而具体的修复细节需要到 changelog 中展开。从 doc/en/changelog.rst 可以看到,6.2.3 唯一一条 Bug Fixes 记录就是 #8414——一个与临时目录权限相关的安全问题。

二、核心修复:临时目录的安全加固(Issue #8414)

2.1 问题描述:两个安全缺陷

根据 changelog 条目,pytest 6.2.3 修复了tmp_path/tmpdirfixture 背后临时目录机制的两个安全缺陷:

缺陷一:临时目录世界可读pytest 曾在/tmp下以世界可读(world-readable)的权限创建目录。这意味着系统上的任何用户都能读取测试写入临时目录的信息(例如由tmp_path/tmpdirfixture 创建的数据)。测试中的敏感信息(token、临时数据、密钥文件等)因此存在被其他用户窥探的泄露风险。

缺陷二:可被预创建并劫持的pytest-of-<username>目录pytest 曾静默复用已经存在的/tmp/pytest-of-<username>目录,即使该目录由其他用户所有。攻击者可以利用这一点:预先创建名为pytest-of-<目标用户>的目录,从而获得对该用户临时目录的控制权(目录劫持 / 抢占)。修复后,遇到此类情况 pytest 会直接报错,而不再默默沿用。

2.2 修复后的行为

6.2.3 之后:

  1. 私有权限创建:临时目录一律以私有权限(Unix 下即0o700)创建,仅所有者可读写执行。
  2. 所有权与类型校验:复用/tmp/pytest-of-<username>前会校验其是否属于当前用户、是否为符号链接,不满足则抛错终止。
  3. 权限修复:对历史上以0o755等世界可读权限遗留的旧目录,会尽力修正权限(出于兼容考虑不直接报错)。

三、源码级解析:安全加固在底层如何落地

当前仓库 src/_pytest/tmpdir.py 完整保留了这套安全机制的实现(6.2.3 引入的逻辑在后续版本中持续演进)。核心代码位于TempPathFactory.getbasetemp()

3.1 基临时目录的创建与所有权校验

在 src/_pytest/tmpdir.py#L156-L205 中,基目录的定位与校验流程为:

  1. 选择临时根目录:优先读取环境变量PYTEST_DEBUG_TEMPROOT,否则使用tempfile.gettempdir()(通常为/tmp)。
  2. 构造用户专属目录rootdir = temproot.joinpath(f"pytest-of-{user}")usergetpass.getuser()获取,失败时回退为pytest-of-unknown,见 get_user())。
  3. 创建与校验:使用mkdir(mode=0o700, exist_ok=True)创建,随后执行一系列安全检查:
    • rootdir符号链接,抛出OSError(防止 symlink-swapping 类 TOCTOU 攻击);
    • 若目录的 UID不是当前用户,抛出OSError,报错信息为"The temporary directory {rootdir} is not owned by the current user. Fix this and try again."
    • 若目录存在世界可读/可写/可执行位st_mode & 0o077 != 0),则通过chmod剥除这些位进行修复。

这段逻辑对应了公告中"静默复用改为直接报错"以及"权限私有化"两个修复点。源码注释(tmpdir.py#L169-L181)也明确说明:历史版本曾使用0o755,因此对遗留目录采取"修复而非直接报错"的兼容策略。

3.2 0o700 私有权限贯穿整个创建链路

私有权限并非只作用于基目录,而是贯穿TempPathFactory的整个创建链路:

  • mktemp()中:非编号目录p.mkdir(mode=0o700),编号目录走make_numbered_dir(..., mode=0o700)(tmpdir.py#L117-L139)。
  • 会话基目录:make_numbered_dir_with_cleanup(..., mode=0o700)(tmpdir.py#L209-L216),同时该函数在src/_pytest/pathlib.py中定义(make_numbered_dir、make_numbered_dir_with_cleanup),统一以mode=0o700创建。

因此,无论tmp_path/tmpdirfixture 生成的具体测试目录,还是它们上层的pytest-<N>编号目录、pytest-of-<user>用户目录,层级结构中的所有目录均为0o700私有权限,任何其他系统用户都无法读取。

3.3 当前测试对修复行为的回归验证

仓库的测试套件直接验证了这套安全机制(基于 Unix 权限,均带有@pytest.mark.skipif(not hasattr(os, "getuid"), reason="checks unix permissions")装饰器,非 Unix 平台自动跳过):

  • testing/test_tmpdir.py#L802-L815test_tmp_path_factory_create_directory_with_safe_permissions:断言新建的basetemp及其父目录(pytest-of-<user>)的权限位满足(stat().st_mode & 0o077) == 0,即无任何世界可读/可写/可执行位。
  • testing/test_tmpdir.py#L818-L839test_tmp_path_factory_fixes_up_world_readable_permissions:先将父目录chmod 0o777模拟历史遗留的坏权限,再重建工厂,断言权限被修复。

这两条测试精确对应 changelog 中"私有权限创建"与"旧目录权限修复"两个行为,是从测试层面印证修复有效性的直接证据。

四、安全影响评估:谁需要关注这个版本

结合 changelog 条目 与 tmpdir.py 的注释 可以推断本次漏洞的威胁模型:

  • 受影响场景:多用户共享主机(如 CI 集群、共享开发机、HPC 节点)上运行 pytest。此时/tmp为共享位置,pytest-of-<username>目录可能被其他用户读取或预创建。
  • 泄露风险:测试写入临时目录的敏感数据(临时凭据、测试密钥、下载的私有构件)可能被其他用户读取。
  • 劫持风险:其他用户可预创建pytest-of-<目标用户>,把文件塞进对方的临时目录,干扰测试或诱导测试读取攻击者控制的文件。

需注意:单用户个人电脑/tmp仅自己使用)通常不直接面临该风险;同时该修复主要针对 Unix 系统,因为 Windows 的临时目录权限模型与 POSIX 不同。

五、升级与验证实操

5.1 升级步骤

作为 drop-in replacement,升级只需一条命令:

pip install --upgrade pytest

升级后建议确认版本号:

pytest --version # 期望输出类似:pytest 6.2.3

5.2 快速验证安全行为

若你运行在 Unix/Linux 环境,可用以下方式验证新版本的权限行为(不修改仓库任何文件,仅在临时环境中执行):

验证一:新建目录为私有权限

# 设置临时根目录并运行一个简单测试 PYTEST_DEBUG_TEMPROOT=/tmp/pytest-demo python -m pytest -p no:cacheprovider --basetemp=/tmp/pytest-demo/base <<'EOF' def test_write(tmp_path): (tmp_path / "secret.txt").write_text("sensitive data") EOF # 检查权限(应输出 700,即无任何 world 位) stat -c '%a' /tmp/pytest-demo/pytest-of-$(whoami)/pytest-0

验证二:目录被其他用户占用时报错

# 以 root 或其他用户预创建"你名下"的目录 sudo mkdir /tmp/pytest-of-$(whoami) && sudo chown root:root /tmp/pytest-of-$(whoami) # 此时运行 pytest 应报错: # OSError: The temporary directory /tmp/pytest-of-<user> is not owned by the current user. python -m pytest --version && ls /tmp/pytest-of-$(whoami)

验证结束后清理演示目录:

sudo rmdir /tmp/pytest-of-$(whoami) # 仅当目录为空 rm -rf /tmp/pytest-demo # 清理演示临时目录

提示:仓库根目录下的tox.inipyproject.toml记录了当前版本的开发/测试环境约束,如需在源码环境复现回归测试,可参考其中配置运行 testing/test_tmpdir.py 中上述两条权限测试用例。

5.3 补充建议

  • 若你的 CI 环境对/tmp权限有额外要求,可显式通过--basetemp指定私有基目录,从而完全绕开系统临时目录的共享问题(对应 tmpdir.py#L150-L155 的_given_basetemp分支)。
  • 若目录所有权校验导致报错(例如历史遗留的pytest-of-<user>目录归他人所有),按报错信息修复该目录的所有权或直接删除后重试即可,新版本不会再静默沿用。

六、版本沿革与参考

  • 版本脉络:6.2.3(2021-04-03)紧随 6.2.2(2021-01-25)、6.2.1、6.2.0 之后发布;6.2.0 起 pytest 仅支持 Python 3.6+(见 doc/en/changelog.rst#L3734)。本次 6.2.3 作为纯 Bugfix 版本,保持与 6.2.x 系列完全兼容。
  • 后续演进:6.2.4、6.2.5 继续在 6.2.x 系列内做 bug 修复,其发布公告可在 doc/en/announce/index.rst 的版本列表中找到。
  • 文档参考:临时目录的完整使用与配置(tmp_path/tmpdir/tmp_path_factorytmp_path_retention_counttmp_path_retention_policy等 ini 选项)可参考 doc/en/how-to/tmp_path.rst。

小结

pytest 6.2.3 虽是一个只有一项修复的 Bugfix 版本,但该修复直击测试框架在多用户环境下最基础的安全薄弱点:临时目录的权限私有化(0o700)与pytest-of-<username>目录的所有权/符号链接校验。无论是通过pip install --upgrade pytest直接升级,还是借助 testing/test_tmpdir.py 中的回归用例验证行为,这一版本都值得所有 pytest 用户在共享主机场景下优先采纳。

【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询