【问题标题】:Is there a way to sandbox test execution with pytest, especially filesystem access?有没有办法使用 pytest 进行沙盒测试执行,尤其是文件系统访问?
【发布时间】:2016-02-10 17:51:38
【问题描述】:

我有兴趣在某种沙箱(如 docker)中使用 pytest 执行可能不受信任的测试,类似于持续集成服务的工作。

我知道要正确沙箱化 python 进程,您需要操作系统级别的隔离,例如在一次性 chroot/容器中运行测试,但在我的用例中,我不需要防止故意恶意代码,只需要防止危险将“随机”函数与参数配对的行为。因此,不太严格的沙盒仍然可以接受。但我没有找到任何支持任何形式的沙盒的插件。

在 pytest 中执行沙盒测试的最佳方法是什么?

更新:这个问题与 python sandboxing in general 无关,因为测试的代码由 pytest 运行,我无法更改它的执行方式以使用 exec 或 ast 或任何。不幸的是,也不能选择使用 pypy-sandbox,因为根据 PyPy feature page,它只是“原型”。

更新 2:pytest-dev 邮件列表中的 Hoger Krekel suggests using a dedicated testuser via pytest-xdist 用于用户级隔离:

py.test --tx ssh=OTHERUSER@localhost --dist=each

which made me realise 用于我的类似 CI 的用例:

拥有一个“一次性”的环境与拥有一个隔离的环境同样重要 一,以便每个测试或每个会话都从相同的初始值运行 状态,并且不受旧会话可能剩余的影响 testuser (/home/testuser, /tmp, /var/tmp, 等)。

所以 testuser+xdist 接近于一个解决方案,但并不完全在那里。

就上下文而言,我需要隔离才能运行pytest-nodev。

【问题讨论】:

标签: python unit-testing testing docker pytest


【解决方案1】:

经过相当多的研究,我没有找到任何现成的方法让 pytest 在操作系统级别隔离和一次性环境中运行项目测试。很多方法都是可行的,各有优缺点,但其中大多数都有更多我会感到舒服的活动部分。

我设计的绝对最小(但固执己见)的方法如下:

  • 使用以下命令构建 python docker 映像:
    • 专用的非root用户:pytest
    • 来自requirements.txt的所有项目依赖项
    • 以开发模式安装的项目
  • 在将项目文件夹挂载到主机上作为pytest用户家的容器中运行py.test

要实施该方法,请将以下 Dockerfile 添加到您要测试的项目的顶部文件夹中,紧邻 requirements.txt 和 setup.py 文件:

FROM python:3

# setup pytest user
RUN adduser --disabled-password --gecos "" --uid 7357 pytest
COPY ./ /home/pytest
WORKDIR /home/pytest

# setup the python and pytest environments
RUN pip install --upgrade pip setuptools pytest
RUN pip install --upgrade -r requirements.txt
RUN python setup.py develop

# setup entry point
USER pytest
ENTRYPOINT ["py.test"]

构建镜像一次:

docker build -t pytest .

在容器中运行 py.test,将项目文件夹作为卷安装在 /home/pytest 上:

docker run --rm -it -v `pwd`:/home/pytest pytest [USUAL_PYTEST_OPTIONS]

请注意,-v 将卷挂载为 uid 1000,因此 pytest 用户无法写入主机文件,uid 强制为 7357。

现在您应该能够使用操作系统级别的隔离来开发和测试您的项目了。

更新:如果您还在主机上运行测试,您可能需要删除容器内不可写的 python 和 pytest 缓存。在主机上运行:

rm -rf .cache/ && find . -name __pycache__  | xargs rm -rf

【讨论】:

  • 您在问题中描述的用例实际上是我一段时间以来最常见的 Docker 用途。这个答案涵盖了使这种方法起作用的大部分细节。 +1 我目前正在努力解决的一件事是如何生成一个 Docker 容器为每个单独的测试以获得测试和操作系统级别的隔离,以及与类似的东西并行化的能力pytest-xdist 插件...
  • 据我所知,这样的用例只能通过专用插件来支持,但我没有找到类似的东西。最接近的是github.com/nvbn/pytest-docker-pexpect,它可以让您编写明确的图像衍生。将核心功能编写为 pytest 插件应该不难,但在插件本身中集成图像设置和维护看起来非常棘手。
  • 我同意。我花了一些时间对此进行调查,但最终因为工作量太大而把这个想法写下来。除了容器管理之外,另一个需要解决的问题是如何让 xdist 之类的东西通过--tx socket=[...] 或类似的方式连接到容器。看起来--tx ssh=[...] 不是一个选项,但使用套接字服务器更加复杂。也许我错了,但我觉得 xdist 本身的扩展将是执行此操作的理想方式,因为那里目前有 --tx 抽象。
【解决方案2】:

老实说,这对于 docker 之类的东西来说似乎是一个很好的用例。当然,仅使用 python 并不能完全干净地处理它,但是您可以随心所欲地滥用主机操作系统,而不必担心长期损害。此外,与许多 CI 解决方案不同,它可以在您的开发机器上轻松运行。

另外请注意,无论您的代码是否是故意恶意的,拥有这种隔离仍然有利于防止以下事故:

rm -rf /usr/local/share/ myapp

【讨论】:

  • 使用一次性容器是我现在正在研究的,令我惊讶的是,但我找不到任何工具来帮助自动化 pytest。
  • 容器将完全包裹在 python 周围,并执行 pytest。 hub.docker.com/_/python 将是一个好的开始,您的 docker 文件将如下所示: FROM python:2-onbuild CMD [ "python", "./test.py" ]
  • 有很多活动部件。您不想将测试烘焙到您的映像中,而是使用--rsyncdir 发送它们并使用--tx ssh= 执行它们。不幸的是,您不能将非标准端口与--tx 一起使用,并且暴露的端口总是放置在非标准位置。
猜你喜欢
  • 2016-07-27
  • 2023-01-28
  • 2011-10-09
  • 2019-10-27
  • 1970-01-01
  • 2013-10-14
  • 2017-01-25
  • 1970-01-01
  • 2018-06-01
相关资源
最近更新 更多