Перейти к основному содержимому

Управление зависимостями: npm, pip, Go modules — playbook

· 7 мин. чтения
Artur Pan
CTO & Co-Founder at PanDev

Обычный JavaScript-сервис импортирует 47 прямых зависимостей и в итоге резолвит 2500+ транзитивных пакетов. Тот же сервис, переписанный на Go, импортирует 12 модулей и резолвит 42. pip-эквивалент — около 180. Это не вкусовщина, это форма каждой экосистемы. Ваша стратегия зависимостей обязана стартовать именно с этой реальности.

Уровень supply-chain-риска, дисциплина lockfile и каденция апгрейдов должны быть разными в каждой экосистеме. Это playbook, как это сделать в npm, pip и Go modules — трёх экосистемах, которые по данным Stack Overflow Developer Survey 2025 покрывают примерно 84% production-кода на бэкенде.

{/* truncate */}

Проблема: одна политика не ложится на три экосистемы

Большинство инженерных организаций пишут один «dependency policy» документ, применяют его ко всем репозиториям и удивляются, почему он везде ощущается неправильно. Он действительно везде неправильный — потому что экосистемы устроены разными компромиссами:

  • npm оптимизирован на ширину. Крошечные пакеты, глубокие деревья, быстрая установка — и история supply-chain-инцидентов (event-stream, ua-parser-js, node-ipc). По данным Sonatype State of the Software Supply Chain 2024, на npm пришлось 68% обнаруженных загрузок вредоносных пакетов в 2023.
  • pip оптимизирован на научные вычисления и системные биндинги. Пакетов меньше, но часто C-расширения, платформенные wheels и резолв-фейлы вида «у меня работает».
  • Go modules оптимизирован на minimal version selection и воспроизводимость. Маленькие деревья, криптографический sum-файл, пиннинг зашит по умолчанию.

Столбчатая диаграмма: среднее число транзитивных зависимостей в npm, pip, Go modules, Cargo Среднее число транзитивных зависимостей для типичного backend-сервиса. Форма экосистемы диктует форму вашей политики.

Это не провал одного и преимущество другого. Это разные ответы на разные задачи, и одна скопированная политика промахивается по реальному риску везде.

Фреймворк: 6 шагов, адаптируемых под экосистему

Шаг 1 — Инвентаризация того, от чего вы реально зависите

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

ПолеПочему важно
Имя + версияБазовая идентификация
Прямая или транзитивнаяПрямую вы фиксите сами; транзитивная — наследство
ЛицензияGPL в проприетарном репозитории — реальный риск
Дата последнего релизаВсё, что не трогали >24 мес. — красный флаг
Число мейнтейнеровОдин человек = bus factor
Тренд скачиванийПадающий пакет часто = заброшенный

Инструменты делают почти всё: npm ls --all, pip list --format=json + pipdeptree, go list -m all. Для лицензий — license-checker (npm), pip-licenses, go-licenses.

Шаг 2 — Дисциплина lockfile для каждой экосистемы

ЭкосистемаLockfileКоммитить?Что в CI
npmpackage-lock.jsonДаnpm ci (не npm install)
pnpmpnpm-lock.yamlДаpnpm install --frozen-lockfile
piprequirements.txt с хешами, или uv.lock / poetry.lockДаpip install --require-hashes
Gogo.sumДаgo mod verify в CI

Контринтуитивная часть: не используйте npm install в CI. Он молча обновляет package-lock.json, если девмашина разошлась с lockfile — именно так скомпрометированная версия просачивается в прод без PR. Всегда npm ci.

Шаг 3 — Каденция апгрейдов по tier

Не все зависимости заслуживают одинакового внимания. Разбейте на тиры:

TierПримерКаденцияAuto-merge?
Runtime + критично по безопасностиopenssl, express, django, golang.org/x/cryptoВ 72 часа после CVEНет (review)
Ядро фреймворкаreact, fastapi, ginMinor/patch в 2 неделиДа, если тесты зелёные
Build-тулингwebpack, ruff, goreleaserМесячный батчДа
Мелкие утилитыlodash.chunk, humanize-durationКвартальный батчДа

Статья Microsoft Research «Keeping Dependencies Updated» (Mirhosseini et al., 2023) показала: команды, которые батчили апгрейды еженедельно, ломали билды из-за дрейфа зависимостей в 2.8 раза реже, чем те, кто апгрейдился по запросу. Механизм очевиден после того, как его увидел: маленькие diff легче биссектить.

Шаг 4 — Поднимите бота, но настройте его по-разному для экосистем

Dependabot и Renovate оба нормально работают. Renovate гибче, Dependabot бесплатен и встроен в GitHub. В любом случае:

# renovate.config.json набросок
{
"packageRules": [
{ "matchManagers": ["npm"],
"matchDepTypes": ["devDependencies"],
"groupName": "npm dev deps",
"automerge": true,
"schedule": ["before 5am on monday"] },
{ "matchManagers": ["pip_requirements"],
"matchPackageNames": ["cryptography", "urllib3", "requests"],
"automerge": false,
"labels": ["security-review"] },
{ "matchManagers": ["gomod"],
"matchUpdateTypes": ["patch"],
"automerge": true,
"groupName": "go patches" }
]
}

Асимметрия намеренная: патчи Go редко что-то ломают, npm dev-deps можно батчить, а pip crypto-смежные библиотеки всегда заслуживают человеческих глаз.

Шаг 5 — Пускайте pipeline через SCA, не только через lockfile

Software Composition Analysis ловит то, чего не видит lockfile: известные CVE в резолвленном дереве. Минимум:

  • npm: npm audit --audit-level=high + osv-scanner
  • pip: pip-audit (официальный от PyPA) + safety check
  • Go: govulncheck (официальный, статический анализ — игнорирует недостижимые пути в коде, что важно при больших транзитивных деревьях в stdlib-смежных модулях)

Тихая суперсила — govulncheck. Он читает реальный call graph и говорит: «CVE есть в твоей зависимости, но твой код туда не доходит». Это убивает огромное количество шума. У npm и pip ничего настолько же точного пока нет.

Шаг 6 — Архивируйте, а не обновляйте формально

Если зависимость не трогали 24+ месяца и её тесты плывут на текущем runtime — не «просто бампните версию». Решите:

  1. Заменить — найти поддерживаемый аналог (momentdate-fns или Temporal API в Node).
  2. Вендоринг — для мелких утилит скопируйте исходник в vendor/ и владейте им сами.
  3. Архивировать сервис — если сам сервис не стоит модернизации, перестаньте тратить время на патчи.

Неприятная правда: 30% тикетов на апгрейд зависимостей в средних репозиториях должны быть решениями «заменить или вендорить», а не апгрейдами. Команды редко это признают, потому что апгрейд ощущается как прогресс.

Типичные ошибки

ОшибкаПочему вредитКак фиксить
npm install в CIДрейф lockfile, тихие смены версийnpm ci
Merge бот-PR без тестов18% апгрейдов что-то ломают (IEEE 2023)Зелёный CI обязателен
Апгрейдить всё разомНе биссектнуть поломкуTier + батч еженедельно
Игнор транзитивных CVEБольшинство эксплойтов приходят через транзитивыSCA в CI, не только lockfile-review
Пиннинг точной версии вездеХрупко, застреваете на CVEПиннинг — для приложений, диапазоны — для библиотек
Общая политика на npm, pip, GoРазные экосистемы = разные рискиРазные политики на разные манифесты

Как понять, что работает

Трекайте по репозиторию по месяцам:

  • Среднее время до патча критического CVE — цель меньше 48 часов для runtime-зависимостей. В книге DORA Accelerate это косвенно связано с change-failure rate.
  • Lockfile drift в CI — число PR, где lockfile меняется неожиданно. Цель — ноль.
  • Процент прямых зависимостей старше 24 месяцев — держите ниже 10%. Выше 20% — медленно тлеющий долг модернизации.
  • Рост транзитивного дерева месяц к месяцу — плато или уменьшение.

PanDev Metrics поднимает метрику «time-to-patch», связывая Git-события с датами раскрытия CVE: когда package-lock.json или go.sum меняется в ответ на известный advisory, это видно в дашборде рядом с остальной работой инженера, без отдельного security-инструмента. Для команд, которые и так считают DORA через нашу платформу, гигиена зависимостей ложится в тот же экран.

Когда этот фреймворк не подходит

  • Чисто исследовательские Python-проекты — научная воспроизводимость часто значит «замёрзнуть на старой версии навсегда». Tiering сверху не работает; используйте uv/conda lockfiles и примите долг как цену воспроизводимости статьи 2022 года.
  • Соло-мейнтейнеры open source — большая часть этого — оверхед, когда вы один. Dependabot + npm audit в CI достаточно. «Тиринг» начинает иметь смысл примерно от 5 контрибьюторов.
  • Строго регулируемые среды (HIPAA, DO-178C) — другая история: SBOM-pipeline, approved vendor lists, provenance-подписи (SLSA, Sigstore). Детали — в нашем гайде по MedTech метрикам.

Честная оговорка: наши данные IDE-heartbeat говорят, сколько времени инженеры тратят на коммиты, связанные с зависимостями, но не скажут, стоил ли конкретный апгрейд стратегически. Это всё ещё зона человеческого решения по release notes.

Что ещё почитать

Готовы увидеть метрики своей команды?

30-минутная персональная демонстрация. Покажем как PanDev Metrics решает задачи именно вашей команды.

Забронировать демо