package-updater Self-update runtime

Самообновление пакетов.
Только подписанные wheel, только HTTPS.

Минимальный, не зависящий от ddp_utils self-update runtime: HTTPS-only проверка обновлений, Ed25519 + SHA-256 подпись артефактов, атомарные транзакции с обязательным rollback-комплектом, изолированный worker-процесс и re-exec после успешной установки.

— модулей
— символов API
— методов
— примеров

Быстрый старт

Прямой вызов или через встроенный дескриптор — оба варианта поддерживаются контрактом.

Явные параметры PackageUpdater.check(...)
from package_updater import PackageUpdater

result = PackageUpdater.check(
    package="nkl-manager",
    repository="nkl-private",
    channel="stable",
    smoke_import="nkl_manager",
)

print(result.status, result.installed_version)
Встроенный descriptor check_declared — предпочтительный вариант
# nkl_manager/__init__.py
from package_updater import PackageUpdater

PackageUpdater.check_declared(package="nkl-manager")

# Только после bootstrap:
from .manager import NklManager
Никакого discovery. Updater никогда не сканирует site-packages, entry points или установленные библиотеки. Каждый пакет инициирует проверку только самого себя, против ровно одного объявленного repository.

Сценарий обновления

Один вызов check() проходит все шаги последовательно; любой шаг может завершиться безопасным возвратом текущей версии.

Идемпотентность в процессе

Повторный вызов check() для того же пакета в одном Python-процессе не повторяет сетевую проверку — возвращается закешированный результат (ключ: identity интерпретатора + путь установки + имя пакета).

Ошибка сети не блокирует запуск

UPDATE_CHECK_FAILED просто означает "текущая версия продолжает работать"; следующая попытка — через 10 минут вместо обычного часового TTL.

Архитектура

BootstrapRuntime — минимальный слой без импорта ddp_utils, безопасный для работы даже во время обновления самого себя.

package_updater PackageUpdater check() · check_declared() · единственная точка входа

Каналы и версии

PEP 440 (packaging.version); строковое сравнение версий запрещено контрактом.

Configured channel Видит offers из
stablestable
betastable + beta
devstable + beta + dev
Bump Policy по умолчанию Поведение
patchautoУстанавливается автоматически
minorautoУстанавливается автоматически
majorwarnMAJOR_UPDATE_AVAILABLE, без авто-установки
dependency downgrade/removepromptТребует confirm-callback, иначе UPDATE_DEPENDENCIES_REQUIRED

Проверка артефактов

Перед тем как wheel попадёт worker'у, он обязан пройти всю цепочку.

HTTPS-onlyЛюбой не-https URL отклоняется на уровне конфигурации
FilenameТолько .whl, без path traversal
IdentityИмя и версия дистрибутива совпадают с ожидаемыми
SizeAdvertised и фактический размер совпадают и не превышают лимит
SHA-256Точное совпадение хеша
Ed25519Подпись проверяется по доверенному key_id

Транзакции и rollback

До изменения окружения обязаны существовать проверенные rollback-wheel для каждого затрагиваемого пакета.

Подготовка (до install)

Скачать и проверить новый wheel → построить dependency plan из METADATA → скачать и проверить rollback wheel текущей версии → снапшот окружения → записать transaction journal. Если rollback-комплект неполный — установка не начинается.

Rollback (после сбоя)

Зависимости откатываются в обратном порядке, затем сам пакет. Успех — UPDATE_FAILED_ROLLED_BACK; неуспех — UPDATE_FAILED_ROLLBACK_FAILED, пакет блокируется.

Locks и recovery

Lock защищает всё окружение целиком, а не только один пакет — зависимости общие.

HEARTBEAT Stale только если

heartbeat истёк и owner_pid больше не существует. Возраст сам по себе не признак stale.

RECOVERY После краха

Следующий вызов находит незавершённую транзакцию и выполняет rollback к snapshot — никогда не продолжает install вслепую.

RE-EXEC После успеха

Restart marker + os.execv, чтобы не остались смешанные версии модулей в памяти процесса.

Конфигурация репозитория

Trust-конфигурация живёт вне wheel и никогда не сканируется/угадывается.

~/.package-updater/repositories.toml или $DDP_UPDATER_CONFIG
[repositories.nkl-private]
check-url = "https://packages.example.com/api/v1/updates/check"
version-fetch-url-template = "https://packages.example.com/api/v1/versions/{package}/{version}"
allowed-packages = ["nkl-manager"]
auth-token-env = "NKL_PACKAGES_TOKEN"

[repositories.nkl-private.trusted-keys]
nkl-release-key-1 = "<base64 Ed25519 public key>"

Статусы результата

UpdateResult.status — единственное поле, которое определяет, что произошло.

NO_UPDATEОбновлений нет либо TTL ещё не истёк
UPDATEDУстановлено и провалидировано успешно
MAJOR_UPDATE_AVAILABLEЕсть major, но auto-policy запрещает
UPDATED_AND_MAJOR_AVAILABLEPatch/minor установлен, major ждёт
MANDATORY_UPDATE_REQUIREDОбязательное обновление без подтверждения
UPDATE_DEPENDENCIES_REQUIREDDowngrade/remove зависимости без confirm
WAITED_FOR_UPDATELock занят другим процессом
UPDATE_INTERRUPTEDОбнаружена прерванная транзакция
UPDATE_FAILED_CURRENT_VERSION_PRESERVEDСбой до изменения окружения
UPDATE_FAILED_ROLLED_BACKСбой после начала, rollback успешен
UPDATE_FAILED_ROLLBACK_FAILEDRollback не удался, пакет заблокирован
UPDATE_CHECK_FAILEDСервер недоступен, текущая версия продолжает работу

Ошибки и диагностика

Каждая ошибка типизирована и имеет стабильный code; секреты в сообщениях не встречаются.

UpdateRepositoryNotConfiguredError Repository id не найден в trust-конфигурации.
UpdateRepositoryNotTrustedError HTTPS нарушен или пакет не в allowed-packages.
ArtifactUntrustedError Filename/identity/size/path-traversal проверка не прошла.
SignatureVerifyFailedError Ed25519 подпись не совпала с доверенным ключом.
RollbackFailedError Не удалось собрать или применить rollback-комплект.
UpdateLockTimeoutError Environment lock занят другим процессом дольше таймаута.
UpdateRecoveryFailedError Восстановление после краха не удалось — пакет заблокирован.

Полный API reference

Все классы, методы и функции библиотеки — с сигнатурами, аргументами, типами и примерами использования.

Проверка…
package-updater Документация сгенерирована из production source.
Наверх ↑