Как загрузить дистрибутив, возможно sdist, не выполняя потенциально файл setup.py (который может содержать вредоносный код)?

Я не хочу рекурсивно получать зависимости, загружаю только один файл для указанного дистрибутива. Попытка, которая не работает:

pip download --no-deps mydist

Вот воспроизводимый пример, демонстрирующий, что setup.py все еще выполняется в приведенном выше случае:

$ docker run --rm -it python:3.8-alpine sh
/ # pip --version
pip 20.0.2 from /usr/local/lib/python3.8/site-packages/pip (python 3.8)
/ # pip download --no-deps suds
Collecting suds
  Downloading suds-0.4.tar.gz (104 kB)
     |████████████████████████████████| 104 kB 13.4 MB/s 
    ERROR: Command errored out with exit status 1:
     command: /usr/local/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-download-yqfdz35d/suds/setup.py'"'"'; __file__='"'"'/tmp/pip-download-yqfdz35d/suds/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-download-yqfdz35d/suds/pip-egg-info
         cwd: /tmp/pip-download-yqfdz35d/suds/
    Complete output (7 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-download-yqfdz35d/suds/setup.py", line 20, in <module>
        import suds
      File "/tmp/pip-download-yqfdz35d/suds/suds/__init__.py", line 154, in <module>
        import client
    ModuleNotFoundError: No module named 'client'
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

Я не могу использовать опцию --no-binary, потому что не хочу исключать исходные дистрибутивы. Я просто хочу избежать выполнения их исходного кода.

16
wim 24 Сен 2018 в 23:36

2 ответа

Лучший ответ

Я копался в pip, и, к сожалению, код там довольно запутанный. Похоже, что в настоящее время нет возможности сделать это, и, согласно ссылке, предоставленной @doctaphred, нет планов добиться прогресса в этом направлении.

Следующий шаг зависит от вашей ситуации; Если, например, вам нужен этот «загрузчик пакетов» для производства, я бы посоветовал вам написать свой собственный клиент pypi. Его было бы очень просто написать, и вы могли бы сделать его намного быстрее и проще, чем pip, оптимизировав его для своих нужд. Для этого вы можете попробовать использовать часть существующего кода в pip, но я думаю, что это, вероятно, будет довольно сложно (после просмотра этого кода).

В противном случае я бы подумал о более быстрых и хакерских методах выполнения работы. Первое решение, которое приходит на ум, - это просто останавливать pip всякий раз, когда он пытается выполнить команду egg_info. Для этого вы можете исправить код pip во время выполнения, используя различные методы. Я предпочитаю использовать файл usercutomize.

Например, создайте файл патча со следующим содержимым и поместите его в каталог по вашему выбору:

/pypatches/pip_pure_download/usercustomize.py :

from pip._internal.req.req_install import InstallRequirement

print('Applying pure download patch!')

def override_run_egg_info(*args, **kwargs):
    raise KeyboardInterrupt # Joke's on you, evil hackers! :P

InstallRequirement.run_egg_info = override_run_egg_info

Теперь, чтобы применить патч к выполнению python, просто добавьте каталог патча в PYTHONPATH, например:

PYTHONPATH=/pypatches/pip_pure_download:$PYTHONPATH pip download --no-deps suds
5
kmaork 20 Фев 2020 в 17:37

Похоже, это невозможно с pip 19.3.1 :(

См. https://github.com/pypa/pip/issues/1884.

1
doctaphred 8 Ноя 2019 в 03:03