n1ro°
RU

Текст и данные · Инструкция

npm audit --audit-level: порог уязвимости и exit code

npm audit --audit-level и exit code часто понимают неправильно: разработчик ожидает «покажи только high», а npm.

Редакция N1RO · Проверено

Короткий ответ

Почему --audit-level не фильтрует отчёт npm audit, а задаёт порог ненулевого exit code. Примеры moderate/high/critical и настройка проверки в CI.

Что делает --audit-level на самом деле

Официальная документация npm формулирует поведение однозначно: `--audit-level` задаёт минимальный уровень уязвимости, который заставляет `npm audit` завершиться с ненулевым exit code, и не фильтрует сам отчёт. Например, при `--audit-level=moderate` наличие только low-уязвимостей не должно падать по этому порогу, но low всё равно могут быть показаны в выводе. Это критично для CI/CD, где «успех» определяется кодом процесса, а человек позже читает лог. Если скрипт дополнительно парсит текст и считает строки, он может получить другую семантику, чем сам npm. Поэтому сначала определите policy: какие severity блокируют merge/deploy, а какие лишь фиксируются как технический долг.

Совет: Не используйте grep по слову «high» как замену exit code npm audit. Текстовый формат отчёта может меняться, а код завершения — штатный машинный сигнал.

Как порог меняет результат команды

  • Команда | Когда audit завершается ненулевым кодом из-за severity
  • npm audit --audit-level=low | При наличии low или более высокой severity.
  • npm audit --audit-level=moderate | При moderate, high или critical; low сам по себе порог не пересекает.
  • npm audit --audit-level=high | При high или critical.
  • npm audit --audit-level=critical | Когда обнаружена critical-уязвимость.

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

Практическая настройка npm audit в CI

  1. 1. Сначала запустите `npm audit` локально и посмотрите реальный набор findings для lockfile проекта.
  2. 2. Сформулируйте правило команды: например, high/critical блокируют merge, moderate создают задачу, low остаются в отчёте.
  3. 3. Закрепите порог явно: `npm audit --audit-level=high`, а не полагайтесь на то, что будущий участник помнит дефолт.
  4. 4. В CI не подавляйте stdout: полный отчёт нужен для понимания, какой пакет и цепочка зависимостей дали finding.
  5. 5. Для машинного архива при необходимости используйте JSON-вывод отдельным шагом, но решение job основывайте на exit code команды.
  6. 6. Если команда упала, сначала разберите рекомендуемое обновление. Не запускайте `npm audit fix --force` автоматически без review, потому что исправление может потребовать несовместимого обновления.
  7. 7. После изменения зависимостей повторите install/ci, тесты приложения и audit, чтобы убедиться, что уязвимость действительно исчезла, а приложение не сломано.

Совет: Если policy меняется, меняйте параметр в одном централизованном CI-шаблоне. Разные audit-level в нескольких workflow быстро дают противоречивые результаты.

Почему отчёт всё равно показывает уязвимости ниже порога

Потому что `--audit-level` не является фильтром отображения. Это удобно: команда безопасности видит полную картину, а pipeline блокируется только по выбранной границе. Путаница возникает, когда разработчик видит в логе `low` и ожидает exit 1 при пороге `high`, либо наоборот считает, что `--audit-level=high` должен убрать строки moderate. Разделяйте две оси: visibility и enforcement. Если вам нужен собственный отфильтрованный dashboard, получайте структурированный audit report и фильтруйте его уже в отдельном инструменте, не меняя смысл `npm audit`. Так CI остаётся предсказуемым: exit code отвечает на вопрос «пересечён ли порог», а отчёт отвечает «что вообще найдено».

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

  • Проверять наличие слова vulnerability в логе вместо фактического exit code.
  • Считать `--audit-level=high` фильтром вывода и удивляться moderate/low в отчёте.
  • Автоматически выполнять `npm audit fix --force` на production-ветке без тестов.
  • Менять порог только ради зелёного CI, не фиксируя принятое security-решение в policy.
  • Игнорировать lockfile: audit анализирует зависимости проекта, поэтому воспроизводимый install важен для повторяемого результата.

Как выбрать audit-level для проекта без магической цифры

Правильный порог зависит от контекста: публичный сервис, внутренний инструмент и локальный прототип имеют разный риск и разный SLA на обновления. Но выбор должен быть явным и проверяемым. Начните с инвентаризации текущих findings, оцените, сколько из них реально достижимы в вашем приложении, и установите уровень, который команда способна оперативно обслуживать. Слишком мягкий порог годами пропускает серьёзные проблемы; слишком жёсткий без процесса исправления превращает audit в кнопку, которую начинают обходить. Хорошая схема оставляет полный отчёт доступным, блокирует по формальной границе и создаёт понятный путь для исключений. Исключение должно быть временным и задокументированным, а не постоянным `|| true`, которое полностью уничтожает смысл проверки.

Почему важны рабочий каталог и версия npm

В монорепозитории заранее решите, где выполняется audit: в корне с единым lockfile или в отдельных пакетах. Две CI-job могут давать разные findings и exit codes при одинаковом названии шага, если читают разные lockfile. Фиксируйте версию Node/npm в сборке и документируйте полную команду, включая рабочий каталог и порог. Тогда разработчик сможет воспроизвести падение локально вместо гадания, почему «тот же npm audit» у него зелёный. Это особенно важно при обновлении major-версии npm, когда формат и детали поведения инструментов могут эволюционировать. Отдельно проверьте обработку exit code самим CI-runner. Некоторые shell-обёртки, `continue-on-error`, `|| true` или пользовательский script могут проглотить ненулевой код npm и оставить job зелёным. Наоборот, строгий shell может остановить job до сохранения JSON-отчёта. Поэтому удобная последовательность — выполнить audit так, чтобы артефакт отчёта сохранился, затем явно передать исходный exit code в статус шага. Это делает поведение понятным и не превращает сбор security-данных в случайный side effect.

Что учитывать

Потому что `--audit-level` не является фильтром отображения. Это удобно: команда безопасности видит полную картину, а pipeline блокируется только по выбранной границе. Путаница возникает, когда разработчик видит в логе `low` и ожидает exit 1 при пороге `high`, либо наоборот считает, что `--audit-level=high` должен убрать строки moderate. Разделяйте две оси: visibility и enforcement. Если вам нужен собственный отфильтрованный dashboard, получайте структурированный audit report и фильтруйте его…

Источники и проверка

Инструкция составлена редакцией N1RO на 2026-09-21. Перед действием сверьте актуальные условия на официальном сайте сервиса или производителя.