Привет всем,
Ситуация
В настоящее время нет простого способа переопределить URL-адрес индекса PyPI по умолчанию, чтобы использовать URL-адрес, указывающий на зеркало. В корпоративной среде довольно часто требуется, чтобы разработчики использовали зеркало репозитория:
К сожалению, это не так просто реализовать в pipenv. Хотя зеркало может быть явно добавлено в Pipfile в качестве источника для этих пакетов, это нарушает переносимость.
Должен быть способ переопределить расположение индекса PyPI, указав (настоящее) зеркало. Это будет применимо только к PyPI, а не к другим сторонним репозиториям (они все равно будут явно указаны в Pipfile).
Общее предложение
Docker приспосабливается к этой ситуации, позволяя пользователю указать зеркало реестра в файле конфигурации демона. Точно так же было бы здорово, если бы пользователь pipenv мог указать (настоящее) зеркало для PyPI с помощью переменной среды, файла конфигурации или параметра командной строки. Если установлено это значение, pipenv должен использовать зеркало для всех пакетов PyPI, даже если доступно подключение к PyPI. В некоторых корпоративных средах PyPI остается разблокированным, но политика требует, чтобы зеркало использовалось по другим причинам, упомянутым выше.
Вопросы реализации
Связанное обсуждение
Это обсуждалось в #python и #pypa на Freenode. После некоторого конструктивного обсуждения было решено, что было бы полезно открыть вопрос здесь для обсуждения. Я ценю все усилия, направленные на решение этой проблемы.
/cc @uranusjr @ncoghlan @altendky @njsmith
Я убежден, что это обычное дело (корпоративный FW/кэширующий прокси) – я чувствую, что нам нужна настройка переопределения, чтобы указать зеркало для использования вместо pypi, если мы найдем его в pipfile – например, PIPENV_PYPI_MIRROR
или PIPENV_PYPI_CACHING_PROXY
или что-то в этом роде, чтобы указать, что сначала следует попробовать, нарезанный на sources
перед pypi в основном.
Это похоже на достижение цели? Если это так, мы можем пометить джинна реализации, чтобы сообщить нам, почему это хорошо или плохо (@ncoghlan)
Я начну с предостережения: пока PyPI не реализовал механизм подписи пакетов, аналогичный PEP 458, чтобы обеспечить независимый от TLS способ для pip
, чтобы гарантировать, что пакеты, которые номинально происходят из PyPI, действительно соответствуют тому, что опубликовал PyPI. , то предложение возможности прозрачного перенаправления трафика на другой сервер действительно важно с точки зрения безопасности.
К сожалению, этот конкретный вектор атаки уже открыт через pip.conf
, поэтому предложение чего-то сопоставимого на уровне pipenv
не сделает ничего хуже, чем оно уже есть.
Кроме того, я думаю, что механизм перезаписи URL репозитория общего назначения на самом деле может быть проще документировать и объяснить, чем что-то специфичное для PyPI, по крайней мере, на уровне базовых возможностей. Что-то типа:
pipenv --override-source-url 'default=https://pypi-proxy.example.com/api' --override-source-url 'https://pypi.python.org/simple=https://pypi-proxy.example.com/api' --override-source-url 'https://pypi.org/simple=https://pypi-proxy.example.com/api' install
(Единственный специфический бит PyPI будет использовать «по умолчанию» для ссылки на источник загрузки pip по умолчанию, как указано в pip.conf
).
Однако каждый раз указывать всю карту переопределения исходного URL-адреса было бы громоздко на практике, поэтому пара вариантов сахара CLI может выглядеть так:
pipenv --override-source-urls <config file> install
pipenv --pypi-mirror https://pypi-proxy.example.com/api install
Другой вопрос, следует ли сразу выставлять слой --override-source-url
— может быть, имеет смысл сначала реализовать более простой вариант --pypi-mirror
и просто сохранить возможность --override-source-url
и --override-source-urls
как возможные варианты будущего.
Моей первой мыслью было также общее сопоставление {given URL: override URL}
, но при дальнейшем рассмотрении есть несколько аргументов в пользу PyPI с особым регистром:
PyPI довольно уникален тем, что имеет хорошо известный общедоступный URL-адрес и множество зеркал.
PyPI на самом деле имеет несколько URL-адресов (например, у нас, вероятно, некоторое время будут плавать Pipfiles с https://pypi.python.org/simple
и https://pypi.org/simple
, а также, возможно, с https://pypi.python.org/simple/
и https://pypi.org/simple/
с косой чертой в конце?), и было бы хорошо, если бы мы могли решить эту проблему один раз, вместо того, чтобы заставлять каждого пользователя разбираться в этом самостоятельно.
@njsmith См. предложение по сахару --pypi-mirror <URL>
в последней части моего сообщения - если первоначальная реализация была сосредоточена исключительно на этом, то общая возможность перезаписи URL-адресов могла бы начаться как внутренняя деталь реализации (управляемая тем фактом, что " PyPI» имеет несколько URL-адресов, которые в конечном итоге приводят к одному и тому же месту), а затем будет рассматриваться как самостоятельная функция позже (после того, как будет подтверждено, что она работает должным образом для основного --pypi-mirror
использования). кейс).
А, точно, пропустил :-)
Существует ли общее правило сопоставления аргументов командной строки с какой-то более постоянной конфигурацией? Я предполагаю, что большинство пользователей этого захотят настроить его один раз, а затем забыть.
@ncoghlan написал:
Я начну с предостережения: пока PyPI не реализовал механизм подписи пакетов, аналогичный PEP 458, чтобы обеспечить независимый от TLS способ для pip, чтобы гарантировать, что пакеты, которые номинально происходят из PyPI, действительно соответствуют опубликованным PyPI, а затем предлагают возможность прозрачное перенаправление трафика на другой сервер действительно важно с точки зрения безопасности.
Если я правильно читаю свой Pipfile.lock
, между пакетом и источником, из которого он был установлен, не сохраняется никакой связи. Учитывая, что существующий набор функций позволяет указать несколько источников, не создает ли это аналогичную проблему? sync
может получить пакет из источника, отличного от того, который использовался при создании файла блокировки.
Pipfile.lock
хранит список допустимых хэшей артефактов для каждой закрепленной зависимости, поэтому после того, как вы сделали блокировку, скрытая замена пакетов будет затруднена. Во время генерации блокировки явный выбор источника в Pipfile
говорит: «Я верю, что этот источник не будет связываться со мной, и буду использовать TLS, чтобы убедиться, что я действительно разговариваю с этой точкой происхождения». (Я думаю, что где-то есть проблема, обсуждающая перспективу привязки определенных пакетов к определенным исходным репозиториям, хотя это может быть в pip
или одном из других репозиториев PyPA, а не здесь)
Изменение URL-адреса индекса по умолчанию (или добавление дополнительного URL-адреса индекса) в pip.conf
или использование предложенной здесь функции переопределения через файл конфигурации или механизм на основе профиля оболочки отличается: это говорит: «Я или какой-то произвольный процесс я запускался в какой-то момент времени с доступом для записи в мой домашний каталог (например, файл setup.py sdist), решил настроить мои параметры так, чтобы доверять этому источнику пакетов». И даже такая схема подписи, как PEP 458, не является полной защитой от такого рода махинаций, если сами открытые ключи, используемые для проверки, хранятся где-то в вашем домашнем каталоге, а не в каталоге, для изменения которого требуются повышенные привилегии.
Есть веские причины, по которым организации со строгими требованиями безопасности выполняют сборки на заблокированных серверах с ограниченным доступом к Интернету в целом или иным образом отслеживают подобные проблемы на сетевом уровне :)
Также обратите внимание, что если вы используете несколько индексов и пакет исходит из неосновного индекса, это будет указано в файле блокировки.
Проблемы pep 458 были, по сути, тем, что я имел в виду, поскольку вещи, которые являются разными URL-адресами, но на самом деле указывают на pypi, отличаются от того, если бы вы просто локально скопировали pypi и заявили, что это одно и то же.
Я или какой-то произвольный процесс, который я запускал в какой-то момент времени с доступом для записи в мой домашний каталог (например, файл setup.py sdist), решил настроить свои параметры так, чтобы доверять этому источнику пакетов.
Если это ваша модель угроз, то я не вижу, как что-либо, что может сделать pipenv, сильно на нее повлияет. Кто-то, кто может изменить конфигурацию вашего домашнего каталога, также может делать такие вещи, как вставка нового каталога в $PATH
и вставка туда фальшивого pipenv, который делает все, что захочет.
@njsmith это также модель угроз pip, поскольку установка пакета требует разрешения выполнения произвольного кода из файлов sdist setup.py
. Этот код действительно может перезаписать что-то в вашем домашнем каталоге, например, ваши настройки, или добавить что-то на ваш путь, или что-то еще. Вот почему явная привилегия pypi (известный, надежный индекс) и требование проверки хэша — хороший шаг к безопасности. Это позволяет централизованно контролировать и устранять известные угрозы безопасности, а также определять проверку пакетов, которые вы загружаете распределенным способом. Что файл блокировки, который вы скачали, говорит о хэше, который вы должны получить? Это не соответствует тому, что вы получаете от индекса? Для того, чтобы этот режим работы дал сбой, у вас должны быть сбои более чем на одном локальном компьютере, индексе и сетевом уровне, потому что вы говорите о наличии нескольких поврежденных пакетов в стеке вашего приложения, работающих согласованно, проверяя хэши по доверенному индексу. , и во многих случаях сами хэши поступали из еще одного постороннего источника. Итак, теперь вам нужно, как минимум, все проверки хэшей как в pip, так и в pipenv каким-то образом подделать так, чтобы он генерировал хэши, идентичные тем, на которые вы надеетесь, но устанавливает еще другие вредоносные вещи?
Я думаю, что я имею в виду, что если ваша локальная машина скомпрометирована, pip или pipenv ничего не сделают, чтобы вас спасти. Но мы можем гарантировать, что загружаемый вами пакет именно тот, который вы искали, из того места, где вы должны были его искать, что может обеспечить один элемент в цепочке безопасности.
@ncoghlan @njsmith как все это влияет на движение против sudo pip install...
и общий смысл, я думаю, у всех нас есть то, что если вы собираетесь использовать пункт, вам, вероятно, не следует также использовать свой менеджер системных пакетов для установки вещей Python в целом. Возможно, на самом деле это не вопрос pipenv, но это то место, где сейчас идет обсуждение, и это может указать на следующие шаги...
@techalchemy Я вообще не вижу связи с этой темой? Я думаю, что вывод из всего вышеизложенного заключается в том, что предоставление пользователям возможности переопределять, какое зеркало pipenv использует для PyPI, не создает никаких дополнительных угроз, а выполнение sudo pipenv
вообще не имеет смысла, верно?
@njsmith нет, я не думаю, что кто-то должен использовать sudo pipenv
, как я уже упоминал, это не совсем по теме, но, поскольку мы немного пошли по пути модели угроз, я подумал, что это стоит изучить. Конкретно:
И даже такая схема подписи, как PEP 458 , не является полной защитой от такого рода махинаций, если сами открытые ключи, используемые для проверки, хранятся где-то в вашем домашнем каталоге, а не в каталоге, для изменения которого требуются повышенные привилегии.
Есть веские причины, по которым организации со строгими требованиями безопасности выполняют сборки на заблокированных серверах с ограниченным доступом к Интернету в целом или иным образом отслеживают подобные проблемы на сетевом уровне :)
Если защита хотя бы в какой-то степени зависит от ключей, хранящихся в привилегированном месте, но мы советуем не использовать привилегированные установки Python, я думаю, что это стоит обсудить. Может быть, я ошибаюсь. Но это определенно похоже на комментарий @ncoghlan (но не sudo pipenv
, этого никогда не должно быть)
Да, это, вероятно, казалось, что это пришло из ниоткуда, просто случайная мысль. Надеюсь, дополнительный контекст прояснит ситуацию.
Я голосую за то, чтобы оставить этот выпуск на тему помощи людям, которым нужно использовать зеркала PyPI, а не вдаваться в спекулятивное обсуждение того, как мы могли бы реализовать TUF. (В любом случае, я не думаю, что мы можем или должны сделать что-то, чтобы попытаться защититься от злоумышленника, который имеет произвольный доступ для записи в домашний каталог пользователя.)
Итак, давайте определим поведение, которое мы ожидаем или предпочитаем. Мое текущее рабочее понимание таково:
--pypi-mirror
или установлено PIPENV_PYPI_MIRROR
, мы должны предпочесть, чтобыОн должен переопределять только PyPI, а не другие URL-адреса. Я предполагаю, что, вероятно, используется всего несколько разных URL-адресов PyPI, поэтому их можно перечислить, и если мы пропустим один, кто-то отправит сообщение об ошибке, он будет добавлен, и довольно скоро у нас будут все они.
Мне кажется правильный подход.
То, что сказал @njsmith , также соответствует моей точке зрения. 3 URL-адреса репо, которые я бы предложил заменить в начальном PR, будут следующими:
pip
)Конечная косая черта, вероятно, лучше обрабатывается как шаг нормализации URL-адресов, а не путем отдельного перечисления URL-адресов.
Обратите внимание, что Pipfile запросов имеет завершающую косую черту (на момент написания) , поэтому нам, вероятно, нужно так или иначе обрабатывать это.
Правильно, моя мысль была:
str.rstrip
, вероятно, будет достаточно для этой задачи, даже если она удалит произвольное количество завершающих косых черт, иначе мы могли бы быть более строгими в отношении этого, и удалите не более одной косой черты в конце)Потрясающий. Я думаю, что этого достаточно для работы и достаточно просто для сборки. Спасибо всем!
Надеюсь, функцию зеркала скоро добавят~
Я также сталкиваюсь с этой проблемой. Ситуация такова:
Моя стратегия развертывания уже устанавливает общесистемный файл pip.conf, который ссылается на внутренний сервер PyPI. Удивительно, но я обнаружил, что эта конфигурация игнорируется Pipenv.
Я замечаю, что если бы я переместил/переименовал внутренний PyPI, то пришлось бы обновить несколько приложений с Pipfiles и восстановить их файлы Pipfile.lock. Зеркальный вариант обеспечит желаемую функциональность. Это также сработало бы и казалось бы менее избыточным, если бы Pipenv мог просто прочитать конфигурацию системы для Pip.
PR приветствуются на этом кстати
Привет. У меня такая же потребность, но я бы разделил эту функцию переопределения на другой билет.
Вот мое ожидаемое поведение:
А во втором тикете могут быть реализованы опции —override. Это имеет смысл, например, внутри CI или что-то в этом роде.
В качестве примечания: сейчас мы активно используем pipenv в производстве, но мне нужно слишком часто напоминать всем, что им нужно вручную изменить свой Pipfile, когда они начинают новый проект, чтобы попасть в наш репозиторий Arrifactory Pypi (для информации, Nexus также делает Pypi кеш бесплатно и отлично работает!). У нас есть очень ограниченный брандмауэр, и внутри компании очень хорошо кэшировать внешние зависимости, чтобы их можно было создать резервную копию и, например, проверить на наличие уязвимостей.
Если простая фича, похожая на общий или пользовательский файл конфигурации (как мы уже делаем для pip или npm), чтобы мы развернули ее на всех наших рабочих станциях, чтобы наши разработчики делали меньше ошибок, это было бы идеально для меня)
Может я что-то пропустил, но это похоже на регресс. Мы некоторое время работали на 11.6.0, и pipenv с радостью делегировал настройки в нашем pip.conf, которые указывают на внутреннее зеркало pypi.
Есть идеи, когда это сломалось? Это делает pipenv совершенно непригодным для использования в нашем контексте. Мне трудно рассматривать это как «отсутствующую функцию», когда она, по-видимому, работала нормально в течение долгого времени.
Для ясности: после обновления до 2018.05.18, даже с зеркалом, указанным в нашем Pipfile[.lock], pipenv пытается установить новые пакеты с pypi.org.
Может быть, то, что я вижу, является отдельной проблемой от этой...
@brettdh Трудно сказать, не видя вашей среды, но я думаю, что это не та же проблема. Я бы посоветовал вам разделить выпуски пополам, чтобы увидеть, где именно это изменилось, и открыть для этого новый выпуск.
Я работаю над PR для этого.
Я действительно думаю, что это было регрессировано по сравнению с настройкой по умолчанию. Возможно, он был пойман волной обновлений для пункта 10, которые еще не выпущены, но я считаю, что мы можем это исправить без особых трудностей, если @JacobHenner еще не добавил его.
Я предполагаю, что вы говорите об использовании devpi в качестве кеширующего прокси для официального PyPi. Для самого pip вам нужно будет изменить /etc/pip.conf
и /usr/lib64/python3.6/disutils/distutils.cfg
, чтобы pip использовал ваш локальный сервер devpi для всех запросов.
Однако похоже, что pipenv игнорирует эти общесистемные настройки, поэтому вы вынуждены изменить параметр конфигурации [[source]]
в Pipfile, чтобы он ссылался на ваш сервер devpi. Но затем, если вы публикуете свой Pipfile извне, внешние участники должны удалить ваши настройки [[source]]
, чтобы фактически создать свою собственную среду.
Я думаю, что pipenv должен просто соблюдать глобальные настройки из /etc/pip.conf
и /usr/lib.../distutils.cfg
@polski-g
Я предполагаю, что вы говорите об использовании devpi в качестве кеширующего прокси для официального PyPi.
Репозиторий Nexus, но да, та же идея.
Однако похоже, что pipenv игнорирует эти общесистемные настройки.
Как упоминал @techalchemy , я считаю, что pipenv (11.6.0) раньше уважал pip.conf
(также и homedir), но последняя версия этого не делает, в частности, где-то есть жестко закодированный URL-адрес pypi.org (зависимость разрешение, IIRC), которое нельзя переопределить.
Я думаю, что pipenv должен просто учитывать глобальные настройки из /etc/pip.conf и /usr/lib.../distutils.cfg
Согласен - хотя лично мне не приходилось изменять distutils.cfg
в моем случае использования.
IIRC принял решение не уважать pip.conf, но вам нужно будет углубиться в средство отслеживания проблем, чтобы найти его. В любом случае, корабль уплыл, и, поскольку зеркалирование PyPI почти завершено, вряд ли это изменится в ближайшем будущем.
Я вполне уверен, что эта функция появится в следующем выпуске (который, если повезет, появится в ближайшие день или два).
Также я не уверен в этом, но, возможно, нам просто нужно вызвать .load()
после того, как мы создадим анализатор конфигурации здесь, чтобы получить настройки по умолчанию.
https://github.com/pypa/pipenv/blob/master/pipenv/project.py#L573 -#L577
@uranusjr , пока работает конфигурация зеркалирования (т. е. не используется тот жестко закодированный URL-адрес pypi.org, о котором я упоминал), я не вижу никаких проблем с тем, что у pipenv есть собственная конфигурация для этого и игнорирование pip.
@brettdh Не могли бы вы проверить мою ветку и подтвердить, что она соответствует вашим
вариант использования в вашей среде?
>
@JacobHenner да, спасибо. Мое первоначальное тестирование с опцией --pypi-mirror
( pipenv install
, pipenv lock
) выглядит нормально. Я оставил небольшое предложение по PR.
Однако я немного обеспокоен тем, что жестко закодированные URL-адреса pypi.org все еще появляются разбросанными по источникам pipenv. Я не могу быть уверен, какие из них правильно переопределены из записей [[source]]
, и я не могу точно вспомнить, какой рабочий процесс вызвал мою проблему выше. Так что трудно сказать, исправлено ли это. 😬
Да, после этого релиза я планирую серьезную очистку кода. Материалы Cli перемещаются в cli, всплывают там исключения и обрабатываются там все выходы, дедуплицируется дублированный код и т. д. Это будет много работы, и помощь будет оценена, если кто-то захочет добровольно :p
Только что вытащил последнюю версию, и она все еще жестко кодирует pypi.org в исходниках. Является ли целью взять переменную среды или pypi-зеркало и установить ее по умолчанию для [[source]]?
редактировать:
Просто копался в коде.. Похоже, у вас есть
if PIPENV_TEST_INDEX:
DEFAULT_SOURCE = {
u"url": PIPENV_TEST_INDEX,
u"verify_ssl": True,
u"name": u"custom",
}
else:
DEFAULT_SOURCE = {
u"url": u"https://pypi.org/simple",
u"verify_ssl": True,
u"name": u"pypi",
}
Я думаю, если бы вы изменили это, если PIPENV_TEST_INDEX на переменную окружения PIPENV_PYPI_MIRROR, это было бы хорошим началом.
Обсуждаемое здесь решение уже давно реализовано. Фрагмент, который вы указали, используется по умолчанию , т.е. используется, если вы не указываете источник при создании Pipfile.
Нет, источник не должен меняться в Pipfile. Цель этого изменения
заключалась в том, чтобы позволить пользователям переопределять URL-адреса PyPI с помощью зеркала, _без_ изменения
Пипфайл.
@JacobHenner Код обработки зеркала выполняет постобработку исходного списка и заменяет URL-адреса pypi.org
ссылками на указанное зеркало.
Это то, что позволяет переопределению зеркала работать , даже если в $#$2$# pypi.org
есть явная запись Pipfile
. Затем pipenv
полагается на ту же логику, чтобы переопределить собственный источник по умолчанию.
Если в настоящее время есть случаи, когда эта постобработка не применяется правильно, это новый отчет об ошибке в отношении уже реализованной функции, а не запрос функции.
Я думаю, что последний комментарий был предназначен для @kylecribbs?
@JacobHenner Ах, извините, я неправильно истолковал ваш комментарий как говорящий о том, что это изменение не достигло своей первоначальной цели, а не как ответ Кайлу, который был направлен на то, чтобы прояснить, каким на самом деле был этот результат.
Самый полезный комментарий
Он должен переопределять только PyPI, а не другие URL-адреса. Я предполагаю, что, вероятно, используется всего несколько разных URL-адресов PyPI, поэтому их можно перечислить, и если мы пропустим один, кто-то отправит сообщение об ошибке, он будет добавлен, и довольно скоро у нас будут все они.