有没有办法用pytest沙箱测试执行,尤其是文件系统访问?
Is there a way to sandbox test execution with pytest, especially filesystem access?
我有兴趣在某种沙箱中使用 pytest 执行潜在不受信任的测试,例如 docker,类似于持续集成服务所做的。
我知道要正确地对 python 进程进行沙箱处理,您需要 OS 级别的隔离,例如 运行 在一次性 chroot/container 中进行测试,但在我的用例我不需要防范故意恶意代码,只需防范将 "randomly" 函数与参数配对的危险行为。因此,不太严格的沙盒可能仍然可以接受。但是我没有找到任何启用任何形式的沙盒的插件。
在 pytest 中执行沙盒测试的最佳方式是什么?
更新:这个问题不是关于python sandboxing in general as the tests' code is run by pytest and I can't change the way it is executed to use exec
or ast
or whatever. Also using pypy-sandbox is not an option unfortunately as it is "a prototype only" as per the PyPy feature page。
更新 2:pytest-dev 邮件列表中的 Hoger Krekel suggests using a dedicated testuser via pytest-xdist 用于用户级隔离:
py.test --tx ssh=OTHERUSER@localhost --dist=each
哪个 made me realise 对于我的 CI 类用例:
having a "disposable" environment is as important as having a isolated
one, so that every test or every session runs from the same initial
state and it is not influenced by what older sessions might have left
on folders writable by the testuser (/home/testuser, /tmp, /var/tmp,
etc).
所以 testuser+xdist 接近解决方案,但还不完全是。
只是为了上下文,我需要隔离到 运行 pytest-nodev。
老实说,对于 docker 之类的东西来说,这似乎是一个很好的用例。当然,仅使用 python 并不能完全干净地处理它,但您可以随心所欲地滥用主机 OS 而不必担心长期损坏。此外,与许多 CI 解决方案不同,它可以 运行 在您的开发机器上舒适地运行。
另请注意,无论您的代码是否有意恶意,拥有这种隔离仍然有助于防止以下事故:
rm -rf /usr/local/share/ myapp
经过相当多的研究后,我没有找到任何现成的方法让 pytest 运行 项目在 OS 级隔离和一次性环境中进行测试。许多方法都是可行的并且各有优缺点,但其中大多数都有更多的活动部分,我会觉得很舒服。
我设计的绝对最小(但自以为是)的方法如下:
- 构建一个 python docker 图像:
- 专用非根用户:
pytest
- 来自
requirements.txt
的所有项目依赖项
- 以开发模式安装的项目
- 运行 py.test 在将项目文件夹安装在主机上的容器中作为
pytest
用户 的家
要实施该方法,请将以下 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。
现在您应该能够使用 OS 级别的隔离开发和测试您的项目。
更新:如果你也在主机上运行测试你可能需要删除python和pytest缓存,它们在容器。在主机上 运行:
rm -rf .cache/ && find . -name __pycache__ | xargs rm -rf
我有兴趣在某种沙箱中使用 pytest 执行潜在不受信任的测试,例如 docker,类似于持续集成服务所做的。
我知道要正确地对 python 进程进行沙箱处理,您需要 OS 级别的隔离,例如 运行 在一次性 chroot/container 中进行测试,但在我的用例我不需要防范故意恶意代码,只需防范将 "randomly" 函数与参数配对的危险行为。因此,不太严格的沙盒可能仍然可以接受。但是我没有找到任何启用任何形式的沙盒的插件。
在 pytest 中执行沙盒测试的最佳方式是什么?
更新:这个问题不是关于python sandboxing in general as the tests' code is run by pytest and I can't change the way it is executed to use exec
or ast
or whatever. Also using pypy-sandbox is not an option unfortunately as it is "a prototype only" as per the PyPy feature page。
更新 2:pytest-dev 邮件列表中的 Hoger Krekel suggests using a dedicated testuser via pytest-xdist 用于用户级隔离:
py.test --tx ssh=OTHERUSER@localhost --dist=each
哪个 made me realise 对于我的 CI 类用例:
having a "disposable" environment is as important as having a isolated one, so that every test or every session runs from the same initial state and it is not influenced by what older sessions might have left on folders writable by the testuser (/home/testuser, /tmp, /var/tmp, etc).
所以 testuser+xdist 接近解决方案,但还不完全是。
只是为了上下文,我需要隔离到 运行 pytest-nodev。
老实说,对于 docker 之类的东西来说,这似乎是一个很好的用例。当然,仅使用 python 并不能完全干净地处理它,但您可以随心所欲地滥用主机 OS 而不必担心长期损坏。此外,与许多 CI 解决方案不同,它可以 运行 在您的开发机器上舒适地运行。
另请注意,无论您的代码是否有意恶意,拥有这种隔离仍然有助于防止以下事故:
rm -rf /usr/local/share/ myapp
经过相当多的研究后,我没有找到任何现成的方法让 pytest 运行 项目在 OS 级隔离和一次性环境中进行测试。许多方法都是可行的并且各有优缺点,但其中大多数都有更多的活动部分,我会觉得很舒服。
我设计的绝对最小(但自以为是)的方法如下:
- 构建一个 python docker 图像:
- 专用非根用户:
pytest
- 来自
requirements.txt
的所有项目依赖项
- 以开发模式安装的项目
- 专用非根用户:
- 运行 py.test 在将项目文件夹安装在主机上的容器中作为
pytest
用户 的家
要实施该方法,请将以下 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。
现在您应该能够使用 OS 级别的隔离开发和测试您的项目。
更新:如果你也在主机上运行测试你可能需要删除python和pytest缓存,它们在容器。在主机上 运行:
rm -rf .cache/ && find . -name __pycache__ | xargs rm -rf