Обновление транзитивных зависимостей с помощью PNPM: Исправление уязвимостей безопасности без поломок
Исправление уязвимостей безопасности может быть сложной задачей, особенно когда речь идет о транзитивных зависимостях. Узнайте, как их обновить, не затрагивая ваши прямые зависимости.
Сегодня уязвимости безопасности являются обычной проблемой в разработке программного обеспечения. К счастью, у нас есть инструменты, такие как GitHub Dependabot, которые помогают нам держать наши зависимости в актуальном состоянии с автоматическим обнаружением и pull-запросами.
Однако это не всегда работает, как ожидалось. Поскольку некоторые зависимости являются транзитивными, их обновление может оказаться сложной задачей для этих инструментов, так как они не знают, какое влияние окажут изменения и какое решение принять при возникновении конфликтов. Нам необходимо справляться с такими случаями вручную.
Методы, которые не работают
- Официальные команды, такие как
pnpm up
, могут испортить ваш файлpnpm-lock.yaml
. Существует проблема по этому поводу, которая до сих пор открыта на момент написания. - Установка последней версии прямой зависимости, которая имеет целевую транзитивную зависимость, может не сработать. Если прямая зависимость не обновила определения версий, транзитивная зависимость не будет обновлена, так как она была разрешена и зафиксирована в файле
pnpm-lock.yaml
.
Решение
Поле overrides
— это мощная функция в PNPM, которая позволяет вам переопределять некоторые разрешения версий. Мы будем использовать эту функцию для обновления транзитивных зависимостей, делая изменения минимальными.
Давайте воспользуемся приведенным выше предупреждением Dependabot в качестве примера. Оно говорит нам, что пакет follow-redirects
имеет уязвимость в безопасности, а исправленная версия — 1.15.6
. Однако прямая зависимость gatsby
использует axios
, которая зависит от [email protected]
.
Шаг 1: Найти транзитивную зависимость
Существует множество способов найти транзитивную зависимость, но я бы порекомендовал самый простой: поиск в файле pnpm-lock.yaml
.
Как насчет "pnpm why"?
Команда pnpm why <package>
действительно полезна. Однако в этом случае она может вас запутать. Например, когда я запускаю pnpm why follow-redirects
, вот часть вывода:
На самом деле в файле pnpm-lock.yaml
существует только одно разрешение для follow-redirects
. Команда pnpm why
может показать вам несколько путей, которые зависят от одной и той же версии пакета.
Шаг 2: Добавьте переопределения
Самый простой случай — это когда в файле pnpm-lock.yaml
существует только одно разрешение. Вы можете добавить переопределение прямо в файл package.json
:
Если вы работаете в рабочей области, добавьте переопределение в корневой файл package.json
рабочей области.
Шаг 3: Примените изменения
Запустите pnpm install
, чтобы применить изменения. Мы можем увидеть, что пакет follow-redirects
обновлен до версии 1.15.6
в файле pnpm-lock.yaml
с минимальными изменениями.
Теперь вы можете удалить поле overrides
из файла package.json
, чтобы сохранить его чистым. Затем заново запустите pnpm install
, чтобы убедиться, что изменения могут быть применены без поля overrides
.
Поиск и устранение неисправностей
Вышеперечисленные шаги — это идеальный случай. Не всегда все идет по плану. Вот несколько советов по устранению неисправностей:
Версия вернулась после удаления поля "overrides"
Это может произойти, если зависимый пакет имеет фиксированную версию или диапазон, который не включает целевую версию. Проверьте файл package.json
зависимого пакета, в данном случае, axios
, чтобы убедиться, что это так.
Если да, вам нужно оставить поле overrides
в файле package.json
, пока зависимый пакет не обновит определения версий.
Существует несколько разрешений для транзитивной зависимости
С ростом проекта файл pnpm-lock.yaml
может содержать несколько разрешений для одного и того же пакета. Например, могут существовать две основные версии одного и того же пакета foo
:
Отчет об уязвимости показывает, что у [email protected]
есть проблема с безопасностью, которая исправлена в версии 1.0.1
, а [email protected]
не затронут. Мы не можем просто добавить переопределение для foo
:
- Если мы добавим переопределение
"foo": "^1.0.1"
, то[email protected]
будет понижен до1.0.1
. Это может сломать проект, так как[email protected]
может иметь новые функции, которые используются в зависимых пакетах. - Если мы добавим переопределение
"foo": "^2.0.0"
, то[email protected]
будет обновлен до2.0.0
. Э то может сломать проект, так как в[email protected]
могут быть внесены изменения, нарушающие совместимость.
Предполагается, что foo
следует семантическому версионированию, поэтому мы можем добавить переопределение следующим образом:
Это обновит только [email protected]
до версии 1.0.1
и оставит [email protected]
без изменений.
Заключение
До тех пор, пока PNPM не поддерживает обновление транзитивных зависимостей напрямую, поле overrides
является хорошим обходным решением для исправления уязвимостей безопасности без поломок. Надеюсь, эта статья поможет вам справляться с такими случаями более эффективно. В Logto мы используем этот метод, чтобы поддерживать наши зависимости в актуальном состоянии и в безопасности.