Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Публикация пакета в PyPI: процесс и безопасность

Публикация пакета в PyPI: процесс, проверка и безопасность

Публикация в PyPI: сборка и проверка дистрибутива, доверенные издатели вместо токенов, тестовый индекс, защита имени и действия при компрометации.

Прямой ответ

Публикация пакета в PyPI состоит из четырёх шагов: сборка дистрибутивов, проверка, загрузка в тестовый индекс, загрузка в основной. Отдельного внимания требует способ аутентификации — он определяет, что произойдёт при утечке учётных данных.

Порядок публикации:

# 1. Сборка sdist и wheel
python -m build

# 2. Проверка метаданных и содержимого
twine check dist/*

# 3. Загрузка в тестовый индекс
twine upload -r testpypi dist/*

# 4. Установка из тестового индекса для проверки
pip install -i  my-package

# 5. Загрузка в основной индекс
twine upload dist/*

Шаг проверки обязателен: он выявляет ошибки описания и отсутствующие файлы до того, как версия станет публичной. Исправление после публикации невозможно — удалённую версию нельзя загрузить повторно под тем же номером.

Аутентификация — основная зона риска. Долгоживущий токен в секрете конвейера при утечке даёт право публиковать вредоносные версии от имени пакета. Механизм доверенных издателей устраняет токен:

Способ Долгоживущий секрет Риск при утечке
API-токен в секрете Да Публикация от имени пакета
Доверенный издатель Нет Ограничен конвейером

Доверенный издатель работает через краткосрочные учётные данные, выдаваемые конвейеру при запуске. Публиковать может только указанный конвейер из указанного репозитория, а постоянного секрета, который можно украсть, не существует; о защите цепочки — в статье про supply chain.

Тестовый индекс нужен для проверки установки, а не для хранения рабочих версий. Пакет в нём не связан с основным, поэтому зависимость из тестового индекса в продуктивной сборке — признак ошибки; о форматах — в статье про wheel и sdist.

Подготовка пакета к первой публикации

Первая публикация отличается от последующих: часть решений необратима, поэтому они принимаются до загрузки.

Имя пакета. Занять имя можно один раз, и оно остаётся за пакетом даже после удаления содержимого. Перед публикацией проверяется, что похожее имя не занято пакетом с иным назначением, поскольку сходство имён используется для подмены.

Метаданные. Описание, классификаторы, адрес репозитория и лицензия отображаются на странице пакета. Их отсутствие не мешает установке, но снижает доверие пользователей и затрудняет оценку пакета.

Классификаторы. Отдельные поля описывают поддерживаемые версии Python, операционные системы и стадию зрелости. Пользователи и инструменты фильтрации используют их при выборе пакета.

Проверка описания. Описание в формате разметки проверяется инструментом до публикации, поскольку ошибка разметки приводит к нечитаемой странице пакета.

Тестовая публикация. Загрузка в тестовый индекс подтверждает, что сборка и загрузка проходят без ошибок, и позволяет проверить установку до основной публикации.

Порядок подготовки:

1. Проверить доступность имени.
2. Заполнить метаданные и классификаторы.
3. Собрать дистрибутивы.
4. Проверить дистрибутивы инструментом.
5. Загрузить в тестовый индекс.
6. Установить из тестового индекса и прогнать проверки.
7. Загрузить в основной индекс.

Каждый шаг обратим до седьмого. После загрузки в основной индекс версия становится публичной, и её номер нельзя использовать повторно.

Практика: безопасная публикация

1. Настройте доверенного издателя вместо токена. Отсутствие долгоживущего секрета устраняет основной сценарий компрометации пакета.

2. Проверяйте дистрибутив перед загрузкой. Инструмент проверки показывает ошибки метаданных, которые после публикации исправить нельзя.

3. Проверяйте установку из тестового индекса. Установка собранного пакета в чистое окружение выявляет пропущенные файлы; о настройке — в статье про структуру пакета.

4. Публикуйте из конвейера, а не с машины разработчика. Публикация из конвейера воспроизводима, а журнал сборки фиксирует, что именно было опубликовано.

5. Используйте двухфакторную аутентификацию для учётной записи. Компрометация учётной записи без второго фактора позволяет передать владение пакетом.

6. Ограничьте число владельцев. Каждый владелец — точка компрометации. Доступ выдаётся по необходимости.

7. Не удаляйте опубликованные версии. Удаление ломает установки с фиксацией версии. Ошибочную версию помечают как отозванную.

8. Фиксируйте версию инструмента публикации. Разные версии могут вести себя иначе при загрузке, что затрудняет воспроизведение.

Рекомендации:

  1. Проверяйте имя пакета до публикации. Занятое имя с похожим написанием — признак намеренной подмены.
  2. Не публикуйте рабочие версии в тестовый индекс. Он предназначен для проверки, и его содержимое может быть удалено.
  3. Ведите журнал публикаций. Дата, версия, автор и коммит — основание для разбора при подозрении на подмену.
  4. Настройте уведомление о новых версиях. Публикация версии, которой вы не выпускали, должна обнаруживаться немедленно.
  5. Разделяйте права на публикацию и на репозиторий. Доступ к коду не должен автоматически давать право публикации.

Практический сценарий: публикация вредоносной версии через утечку токена

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

  1. Диагностика. Уведомление о новой версии пришло, но соответствующего коммита и сборки в конвейере не было. Версия содержала код, обращающийся к внешнему адресу при импорте.
  2. Причина. Токен с правом публикации хранился как долгоживущий секрет и был доступен всем, кто имел доступ к настройкам конвейера. Компрометация одного из них дала право публикации.
  3. Действия. (а) Версию отозвали, чтобы установка по умолчанию её не получала; (б) токен немедленно отозвали; (в) публикацию перевели на доверенного издателя, исключив долгоживущий секрет; (г) проверили журнал загрузок за год и убедились в отсутствии других несанкционированных версий; (д) включили двухфакторную аутентификацию для всех владельцев; (е) уведомили пользователей об отозванной версии.
  4. Результат. Публикация возможна только из указанного конвейера, а постоянного секрета, который можно украсть, больше нет.

Вывод: долгоживущий токен публикации — единственная точка компрометации, дающая право выпускать версии от имени пакета. Доверенный издатель устраняет секрет и ограничивает публикацию конкретным конвейером, что снижает последствия утечки учётных данных.

FAQ

Можно ли удалить опубликованную версию? Версию можно отозвать, но повторная загрузка под тем же номером невозможна. Поэтому проверка выполняется до публикации.

Зачем нужен тестовый индекс? Для проверки установки собранного пакета. Версии в нём не связаны с основным индексом и могут быть удалены.

Что делать при подозрении на компрометацию? Отозвать токен, отозвать подозрительные версии, проверить журнал загрузок и перевести публикацию на доверенного издателя.

Сколько владельцев должно быть у пакета? Минимально необходимое число. Каждый владелец — дополнительная точка компрометации, требующая двухфакторной аутентификации.

Источники: Python Packaging User Guide, PyPI docs (Trusted Publishers, API token) — ссылки в шапке.