Skip to content
Apothem
Справочник

Манифест закрепления зависимостей

Политика объявления зависимостей, охватывающая диапазоны среды выполнения Python, инструменты разработки, lock-файлы инструментов релиза и утверждённые нижние границы версий для каждой поверхности сборки.

Утверждённая позиция о том, как Apothem объявляет, закрепляет и блокирует зависимости. Аудитория: участники и нижестоящие потребители, которым нужно понять модель воспроизводимости.

Позиция

Apothem — это Python CLI с небольшим набором зависимостей среды выполнения плюс более крупная цепочка инструментов для разработки, аудита, релиза и документации. Зависимости среды выполнения используют консервативные нижние границы в pyproject.toml; сайт коммитит site/package-lock.json; GitHub Actions закреплены по неизменяемому SHA с комментариями версий и обновляются через Dependabot.

КлассОбъявлениеПолитика блокировки
Зависимости среды выполнения Python[project.dependencies] в pyproject.tomlДиапазоны с нижней границей для пользователей; lock среды выполнения Python в пакет не входит. CI устанавливает их замыкание, заблокированное по хешу (см. Lock-файлы зависимостей CI)
Инструменты разработки / безопасностиextras из [project.optional-dependencies]Диапазоны с нижней границей, кроме ruff и mypy: extra dev точно закрепляет их на версиях, которые запускает CI (для ruff см. Lock-файлы инструментов CI); CI устанавливает extra dev из замыкания, заблокированного по хешу (см. Lock-файлы зависимостей CI)
Инструменты релизаscripts/release/requirements-build-linux.txt для рабочих процессов релиза; extra release в [project.optional-dependencies] для локальных сборокЗаблокированы по хешу для рабочих процессов релиза; сгенерированы из замыкания инструментов релиза. Extra release — диапазон с нижней границей
pip для CIscripts/ci/requirements-ci-pip.txtЗаблокирован по хешу: одно закрепление pip==X.Y.Z с хешами его wheel и sdist; каждый рабочий процесс, обновляющий pip, устанавливает его с --require-hashes -r. Dependabot предлагает обновления и переписывает хеши; scripts/dev/check_pip_pin_drift.py держит закрепление на pip 26.2 или новее
Lock-файлы зависимостей CIscripts/ci/requirements-ci-dev.txt, -runtime.txt, -test.txt и -prereqs.txtУниверсальные замыкания, заблокированные по хешу. Они компилируются с помощью uv pip compile из pyproject.toml (а для -prereqs.txt — из требований движка к хосту) на дату блокировки за вычетом 7-дневного периода ожидания; оба значения записаны в каждом файле. Устанавливаются с --require-hashes -r (сам пакет — с --no-deps -e .). CI тестирует заблокированные версии, пока scripts/dev/refresh_ci_locks.py не сгенерирует их заново; pip-audit.yml еженедельно проверяет новейшие допустимые версии, а также сами lock-файлы. tests/scripts/test_ci_locks_fresh.py падает, когда lock-файл больше не удовлетворяет своим входным данным
Lock-файлы инструментов CIscripts/ci/requirements-ci-ruff.txt, -bandit.txt, -pip-audit.txt, -pip-licenses.txt и -pre-commit.txtПо одному замыканию, заблокированному по хешу, на каждый инструмент, который запускают рабочие процессы. Их компилирует тот же скрипт по точной спецификации из scripts/dev/ci_lock_table.py, с той же датой блокировки и тем же периодом ожидания, а устанавливаются они с --require-hashes -r. Ни один рабочий процесс не указывает версию инструмента. pre-commit требует Python 3.11 или новее, поэтому и его lock-файл тоже, а lock-файл pip-audit тоже компилируется для 3.11, потому что у новейшего filelock с поддержкой 3.10 есть неисправленные уязвимости. Кроме lock-файла pip для CI, ни один lock-файл не закрепляет pip
Сайт документацииsite/package.jsonsite/package-lock.json закоммичен и потребляется npm ci
Упаковщик VS Codetools/vsce/package.jsontools/vsce/package-lock.json закоммичен; задания релиза и публикации запускают npm ci --ignore-scripts
CLI окружений для channel-smoketools/channel-smoke/package.jsontools/channel-smoke/package-lock.json закоммичен и потребляется npm ci
GitHub ActionsЗакреплённые по SHA ссылки uses: с комментариями версийDependabot еженедельно предлагает обновления; исключения несут маркеры action-pinning-exempt:

Утверждение релиза

ПоверхностьУтверждённое состояниеОбоснование
Зависимости среды выполненияТекущие нижние границы находятся в pyproject.toml, в [project.dependencies]Текущие стабильные нижние границы утверждены до релиза; известных блокеров по CVE среды выполнения нет
Инструменты разработкиТекущие нижние границы находятся в extra dev файла pyproject.toml; ruff и mypy закреплены там точноПоследние стабильные нижние границы утверждены до релиза; ruff и mypy закреплены каждый на одной версии для хуков, CI и участников, хук mypy закрепляет перечисленные в нём библиотеки на версиях из lock-файла dev, а tests/scripts/test_ci_tool_locks.py падает при расхождении
Инструменты безопасностиТекущие нижние границы находятся в extra security файла pyproject.tomlТекущие нижние границы сканеров утверждены до релиза
Инструменты релизаЗамыкание с фиксацией по хешу находится в scripts/release/requirements-build-linux.txtРабочий процесс релиза устанавливает с --require-hashes; локальные скрипты требуют, чтобы build уже существовал, вместо тихой установки изменяющихся зависимостей
pip для CIЗакрепление, заблокированное по хешу, находится в scripts/ci/requirements-ci-pip.txtpip 26.2 или новее закрывает CVE-2026-13346; рабочие процессы устанавливают его с --require-hashes, поэтому загрузка сверяется с опубликованным хешем
Lock-файлы зависимостей CIЗамыкания с фиксацией по хешу находятся в scripts/ci/requirements-ci-{dev,runtime,test,prereqs}.txtРабочие процессы устанавливают их с --require-hashes; каждый файл записывает свою дату блокировки, период ожидания и граничную дату, а тест актуальности держит их синхронными с pyproject.toml
Lock-файлы инструментов CIЗамыкания с фиксацией по хешу находятся в scripts/ci/requirements-ci-{ruff,bandit,pip-audit,pip-licenses,pre-commit}.txtРабочие процессы устанавливают их с --require-hashes и не указывают версий инструментов; спецификации находятся в scripts/dev/ci_lock_table.py, а дата блокировки, период ожидания и граничная дата совпадают с lock-файлами зависимостей
Инструменты документацииТекущие диапазоны находятся в site/package.json; точное разрешение — в site/package-lock.jsonnpm outdated после обновления lock-файла не возвращает устаревших зависимостей документации
GitHub ActionsСуществующие закрепления по SHA сохранены для текущего релиза; повторно используемый рабочий процесс SLSA остаётся задокументированным исключением, закреплённым по тегу и отмеченным комментарием action-pinning-exempt: в release.ymlПовторный прогон публичного CI зелёный; широкие обновления мажорных версий Actions намеренно оставлены PR автоматизации зависимостей, чтобы не вносить постоянных изменений в поверхность релиза
Упаковка npmРабочий процесс publish-npm.yml запускается при push тега v*.*.*, а workflow_dispatch — запасной вариантЕдинственный публичный npm-пакет — @ahmed-g-gad/apothem; публикация ожидает одобрения оператором среды release, которое даётся после прохождения scripts/release/check-release-ready.sh

Блокировка

Собственные lock-файлы Python участники генерируют по требованию, и они не коммитятся: замыкание среды выполнения Apothem невелико, а CLI поддерживает несколько минорных версий Python. Исключение — CI. Он устанавливает заблокированные по хешу файлы из scripts/ci/: четыре lock-файла зависимостей (requirements-ci-dev.txt, -runtime.txt, -test.txt и -prereqs.txt) и по одному lock-файлу на каждый инструмент, который запускают рабочие процессы (-ruff.txt, -bandit.txt, -pip-audit.txt, -pip-licenses.txt и -pre-commit.txt). python scripts/dev/refresh_ci_locks.py компилирует все девять на дату блокировки за вычетом 7-дневного периода ожидания, как у Dependabot. Поэтому CI тестирует релизы, которым на дату блокировки исполнилась хотя бы неделя, а обновление файлов сдвигает их вперёд. Каждый файл записывает дату блокировки, период ожидания и итоговую граничную дату, а --check воспроизводит эту граничную дату. Срочному исправлению безопасности, которое моложе периода ожидания, нужен запуск обновления с --cooldown-days 0 или исключение из периода ожидания для его пакета в scripts/dev/ci_lock_table.py; такое исключение снимает период ожидания только для этого пакета. Еженедельный запуск pip-audit.yml проверяет новейшие версии, которые допускает pyproject.toml, а также все девять lock-файлов и запрашивает у сервиса OSV сведения об уязвимостях. Участники по-прежнему устанавливают пакет командой pip install -e ".[dev]".

# Astral uv:
uv pip install -e ".[dev,security,release]"
uv pip freeze > requirements.dev.lock

# pip-tools:
pip-compile --extra=dev --extra=security --extra=release -o requirements.dev.lock pyproject.toml

# Plain pip:
pip install -e ".[dev,security,release]"
pip freeze > requirements.dev.lock

Сайт устроен иначе: site/package-lock.json коммитится, а CI использует npm ci, поэтому отрендеренный сайт документации имеет воспроизводимое замыкание Node.

Обоснование

  • Почему диапазонные закрепления для Python? CLI поддерживает широкую матрицу Python, поэтому pyproject.toml задаёт консервативные нижние границы. CI устанавливает заблокированные по хешу замыкания этих диапазонов, которые сопровождающий обновляет с помощью scripts/dev/refresh_ci_locks.py (задуманный ритм — раз в неделю), а еженедельный запуск pip-audit.yml разрешает новейшие допустимые версии, чтобы выявить проблемы с текущими инструментами.
  • Почему закоммиченный lock Node? Сайт — это развёрнутый статический артефакт; lock-файл даёт детерминированные сборки npm ci для этой публичной поверхности.
  • Почему закреплённые по SHA Actions? Теги изменяемы; SHA неизменяемы. Dependabot предлагает повышения SHA и переписывает каждый комментарий версии, а шлюз релиза фиксирует любое намеренное удержание версии.
  • Чего бот обновлений не касается. Обновления версий Dependabot (.github/dependabot.yml) охватывают закрепления GitHub Actions, lock-файл сайта, lock-файл упаковщика vsce (tools/vsce), lock-файл CLI окружений, который устанавливает channel smoke (tools/channel-smoke), заблокированный по хешу pip, который устанавливает CI (scripts/ci/requirements-ci-pip.txt), и хуки pre-commit. Остальные девять файлов в scripts/ci — это замыкания, которые scripts/dev/refresh_ci_locks.py генерирует заново целиком; ни один из них не закрепляет pip, и обновления версий Dependabot для этой папки ограничены pip. Нижние границы среды выполнения в pyproject.toml, заблокированные по хешу требования релиза, вендорное замыкание в src/apothem/_vendor/vendor.txt и хуки pre-commit, закреплённые синхронно с pyproject.toml, обновляются вручную, потому что повышение одного закрепления сломало бы файлы, с которыми они согласованы. Хуки ruff и mypy — два из них: tests/scripts/test_ci_tool_locks.py падает, пока точное закрепление ruff в pyproject.toml, rev хука, lock-файл ruff и lock-файл dev не укажут одну и ту же версию и пока точное закрепление mypy, rev хука mypy и библиотеки, которые перечисляет этот хук, не совпадут с lock-файлом dev. Поэтому pull request безопасности от Dependabot для любого из этих инструментов адаптируется вручную. Мажорная версия @types/node сайта следует за его нижней границей Node (engines и .nvmrc, Node 22), поэтому Dependabot предлагает только её минорные и патч-обновления; повышайте эту мажорную версию вместе с нижней границей. Обновления версий не трогают блоки npm overrides. Обновления безопасности Dependabot по-прежнему охватывают каждый манифест, поэтому pull request безопасности может предложить одно из этих закреплений или сдвинуть override; адаптируйте его вручную или закройте.
  • Слияние pull request от Dependabot. Squash по умолчанию в репозитории берёт заголовок PR. Некоторые заголовки Dependabot, в основном групповые, называющие каталог, превышают 72 символа темы squash-коммита; проверка PR Title называет их, а смена заголовка их исправляет. Pull request, изменяющий lock-файл инструмента, не запускает ни одного задания ci.yml, поэтому рабочий процесс npm audit проверяет и устанавливает его, упаковывает расширение VS Code для lock-файла vsce и запускает тесты релиза vsce, а рабочий процесс channel smoke запускается для lock-файла channel-smoke. Рабочий процесс Markdown Lint запускает хук markdownlint на pull request с хуками pre-commit; остальные хуки в CI не проверяются, поэтому перед слиянием запустите pre-commit run --all-files на его ветке.

On this page