Система раннего предупреждения для зависимостей, за которыми вы перестали следить.
В эпоху ИИ вы выпускаете больше проектов, чем способны поддерживать. Sentinello следит за каждым из них и выявляет известные CVE в их зависимостях Node.js — чтобы забытый проект никогда не превратился в инцидент.
Запустите одной командой:
docker run -d \
--name sentinello \
-p 127.0.0.1:3870:3000 \
--stop-timeout 60 \
-v sentinello-data:/app/data \
-v sentinello-nvm:/home/sentinello/.nvm \
-v ~/Developer:/roots/personal:ro \
ghcr.io/walkofcode/sentinello:latestРаботает на linux/amd64 и arm64
Без аккаунта. Без SaaS. Без телеметрии. Один образ Docker и один файл SQLite — ваш код и результаты никогда не покидают вашу машину.
Или обойдитесь вовсе без портала
Те же сканеры поставляются как CLI. Без установки, без аккаунта, без базы данных: запускается, печатает сводку, с которой может работать ваш агент, и завершается.
npx sentinelloВ конвейере stdout несёт только markdown, поэтому сводка доходит до агента без искажений:
npx sentinello | claude -p "$(cat -)"Обходит папку
Укажите каталог — и он найдёт все проекты внутри, останавливаясь на корне каждого, чтобы монорепозиторий считался один раз, а не пятьдесят. .gitignore и .sentinelloignore учитываются.
Проверяет три источника
Определяет точные установленные версии из lock-файла и сверяет их офлайн с локальным кэшем сводок. Ни одного сетевого запроса на проект, и ничего из вашего кода не отправляется наружу.
Пишет сводку
Датированный markdown-файл с находками и приложенным промптом по устранению: сначала разобрать, предпочитать обновление родительского пакета переопределениям, проверять исправления в lock-файле.
Чем это отличается от npm audit
Это не замена npm audit: он запускает npm audit, а затем добавляет два источника сводок, недоступных npm audit, подавляя всё, что дублируется.
| npm audit | npx sentinello | |
|---|---|---|
| Охват | Единственный проект, в котором вы находитесь. | Все проекты внутри папки — за один проход и в одном отчёте. |
| Источники сводок | Лента сводок вашего реестра. | Она же, плюс OSV и GitLab gemnasium. Дубликаты подавляются, поэтому каждый дополнительный источник добавляет только новые находки. |
| Вредоносные пакеты | Не покрывается. | Записи MAL- в OSV отмечают пакеты, опубликованные с вредоносным кодом — тайпсквоттинг, полезная нагрузка в install-скриптах — сверяя их с конкретными скомпрометированными версиями. |
| Вывод | Таблица или JSON, который нужно интерпретировать. | Markdown-сводка с приложенным промптом по устранению, готовая для передачи агенту. |
| Сопоставление | Запрос к реестру на каждый проект. | Офлайн, по локальному кэшу. Первый запуск скачивает его, предварительно спросив; последующие передают почти ничего. |
Дополнительные источники — не формальность. В собственном репозитории Sentinello npm audit и OSV сообщают по три находки и совпадают во всех, тогда как единственная критическая находка приходит из gemnasium, которого нет ни в одном из двух других.
Возможности
Всё в одном самостоятельно размещаемом портале — никаких внешних сервисов, данные не покидают вашу сеть.
Единая очередь триажа
Просматривайте и сортируйте CVE всего портфеля в одном месте — вместо npm audit, разбросанного по десятку чекаутов.
Просмотр по проектам или библиотекам
Откройте любой репозиторий, чтобы увидеть его находки, версии с исправлением и историю, — или переключитесь на уязвимый пакет, чтобы увидеть каждый затронутый им проект и заглушить его сразу везде.
Находки, которые совпадают
Когда одну и ту же уязвимость сообщают несколько источников, находка остаётся одной — она несёт с собой, кто именно совпал, и оценивается по худшей серьёзности, которую дал любой из них.
Непрерывное сканирование
Фоновый процесс пересканирует по расписанию, поэтому новые рекомендации появляются без того, чтобы вы помнили о проверке.
Несколько источников
Не только npm audit: сопоставление с OSV и с gemnasium от GitLab для более широкого охвата CVE и обнаружения известных вредоносных пакетов.
Уведомления и вебхуки
Получайте оповещения о сбоях и находках через Slack, Telegram или обычный вебхук — с привязкой к конкретному корню или проекту, на выбранном вами языке. Полезная нагрузка в формате JSON или обычного текста для агента автоисправления.
MCP-сервер
Подключите Claude Desktop, Cursor и другие MCP-клиенты, чтобы запрашивать результаты, проекты и библиотеки — и запускать сканирование — не покидая чат.
Экспорт рекомендаций
Экспортируйте находки проекта или библиотеки в Markdown с настраиваемой подсказкой для устранения — для вашей команды или LLM.
Один образ, один файл
Один образ Docker и один файл SQLite. Никакого сервера баз данных, очереди сообщений или зависимости от облака.
Автоматически регистрируемые roots
Всё, что смонтировано в /roots, регистрируется и сканируется при запуске — имя каталога становится его меткой.
Node для каждого проекта
Учитывает .nvmrc каждого проекта, устанавливая и кэшируя зафиксированную версию Node один раз.
10 языков
Интерфейс портала, коды причин сканирования и статусы локализованы на 10 языков.
Скриншоты
Посмотрите в действии — портал сканирует несколько демонстрационных проектов. Нажмите на любой снимок, чтобы увеличить.
Сравнение
Sentinello — не более тяжёлый Dependency-Track и не более дешёвый Snyk. Он занимает другую нишу: длинный хвост проектов, которые никто не подключил к конвейеру.
| Sentinello | Dependency-Track | Snyk | Dependabot | |
|---|---|---|---|---|
| Без настройки — укажите папку | ~ | ~ | ||
| Не нужен SBOM / шаг CI | ||||
| Сканирует реальные разрешённые lockfile | ~ | |||
| Обнаружение вредоносных пакетов | ||||
| Self-hosted, без SaaS | ||||
| Один образ + SQLite | ||||
| AI-native (MCP + экспорт) | ~ | |||
| Полиглот (Python, Go, …) | ||||
| Корпоративные политики / VEX | ~ | ~ |
Dependency-Track видит только проекты, которые кто-то оснастил конвейером SBOM. Sentinello находит забытые. Они сильнее в корпоративных политиках; если вы уже используете их в зрелом конвейере, оставьте их. Sentinello — для остальной части вашего портфеля, за которой никто не следит.
Зачем мы это создали
В эпоху ИИ вы выпускаете больше, чем способны поддерживать.
Сегодня один разработчик за год запускает, сдаёт и оставляет позади десяток проектов — маркетинговый сайт, клиентскую панель, пет-проект, который тихо ушёл в продакшн. Чтобы держать их в безопасности, раньше приходилось заходить по SSH в каждый чекаут и вручную запускать npm audit — или узнавать о CVE в Next.js из заголовков, спустя дни после публикации. Никто не делает этого по десятку репозиториев, так что этого не происходит вовсе.
Достаточно одной забытой зависимости с критической уязвимостью удалённого выполнения кода. Самый простой сайт, за которым вы перестали следить, становится точкой входа.
«Почему просто не взять Snyk или Dependabot?» Они живут внутри CI-конвейера, который вы настроили, — а длинному хвосту такой конвейер так и не достался. Sentinello — это система раннего предупреждения для всего остального: укажите ему папку, и он будет следить за каждым забытым проектом, выводя каждый новый CVE в одну очередь — прежде чем он превратится в инцидент.
Как это работает
Три шага. Никаких агентов для установки в ваши проекты, никаких аккаунтов.
Укажите ему свой код
Смонтируйте репозитории в /roots или добавьте их в «Настройки → Roots». Каждый каталог автоматически регистрируется и обнаруживается при запуске.
Непрерывное сканирование
Фоновый процесс по расписанию сверяет ваши зависимости с известными CVE, устанавливая нужную версию Node, которую фиксирует каждый проект, когда это требуется.
Триаж в одной очереди
Каждая находка из каждого проекта попадает в единую очередь, которую можно фильтровать по серьёзности, — с опциональными оповещениями в Slack, Telegram или вебхук.
Для кого это
Sentinello — для всех, у кого в продакшне больше, чем они способны охватить взглядом: для тех, кто разрабатывает в одиночку, для небольшой команды, для агентства, жонглирующего клиентскими проектами.
- Вы выпускаете пет-проекты и клиентские сайты, которые должны оставаться безопасными ещё долго после запуска.
- Вам нужен обзор всего портфеля без подключения CI к каждому репозиторию.
- Вы предпочитаете размещать у себя, а не отдавать опись своего кода SaaS-сервису.
Если вы крупная организация, у которой Snyk или Dependabot уже встроены в зрелый конвейер, оставьте их — Sentinello не пытается заменить корпоративный SCA. Он здесь для остальной части вашего портфеля, за которой никто не следит. Он с открытым кодом и под лицензией MIT, так что вы можете в точности прочитать, что он делает.
Примечания к выпуску
Sentinello регулярно обновляется — вот что появилось в каждой версии.
Панель, где один источник говорил за весь проект
v3.5.0 · 20 авг. 2026 г.- Столбец <strong>Состояние</strong> на панели сообщал об одном источнике и отбрасывал остальные. Каждое сканирование пишет по строке на источник, и они завершаются с разницей в миллисекунды, поэтому в столбце оказывался тот, что закончил последним — на практике всегда OSV. Каждый проект показывал «База данных OSV ещё не загружена», хотя npm audit прекрасно их просканировал и нашёл настоящие уязвимости. Теперь Состояние несёт по значку на каждый источник, который не смог ответить, с указанием источника, и не показывает ничего, когда все включённые источники в порядке. В истории сканирований по той же причине появился столбец <strong>Источник</strong>: один проход писал три одинаковых на вид строки, которые нельзя было различить.
- Настройки → Источники утверждали, что кэш актуален, пока он перестраивался. Состояние, которое читает портал, записывалось только по завершении синхронизации, поэтому на протяжении всей многоминутной перестройки оно продолжало показывать прежнее количество — тогда как каждое сканирование справедливо отвергало наполовину удалённый кэш. Оно также никогда не несло версию нормализатора, которую требует сканер, так что смена версии порождала то же ложное утверждение вообще без перестройки. Теперь строка читается как <strong>Перестроение…</strong> с приглушённым прежним количеством или <strong>Ожидает перестроения</strong>, когда кэш непригоден и им никто не занимается.
- Догрузившийся кэш оставлял каждый проект с тем вердиктом, который тот получил, пока кэша не было. Ничто не пересканировало, поэтому <code>osv_db_not_seeded</code> держался до следующего планового прохода — или пока вы не замечали и не нажимали «Сканировать». Теперь Sentinello ставит в очередь один полный пересканинг, как только кэш снова становится пригодным. Инкрементное обновление не ставит в очередь ничего. Обновление тоже учитывается: если этот выпуск попадёт на инстанс, чьи проекты всё ещё несут вердикт, вынесенный до завершения кэша, воркер заметит расхождение при первом запуске и устранит его за вас — не нужно помнить про запуск сканирования.
Уведомление, помечавшее версию, которая его и исправила
v3.4.0 · 18 авг. 2026 г.- gemnasium записывает небольшое число уведомлений с пробелом между оператором сравнения и версией — <code>< 0.5.2</code> вместо <code><0.5.2</code>, — и анализатор читал эту пару как два отдельных токена. Осиротевший <code><</code> получал пустую границу, а оставшаяся сама по себе версия попадала в кэш как точно закреплённая. Поэтому уведомление для <code>fresh</code> сообщало о версии 0.5.2 как об уязвимой, хотя именно 0.5.2 и является выпуском, который всё исправил, — и сообщало без доступного исправления, поскольку закреплённая версия не несёт никакой цели обновления. Так записаны 19 уведомлений, и все они разбирались неверно: 15 полностью теряли свой диапазон, а 7 закрепляли версию, которую сама запись называет исправлением; <code>pg</code> закреплял одиннадцать.
- Sentinello перестал сам толковать синтаксис диапазонов npm и теперь сначала передаёт каждый диапазон собственной реализации npm, что разом закрывает целое семейство неверных прочтений. Для npm <code><=3.3</code> означает «до конца линейки 3.3» — при буквальном чтении всё останавливалось на 3.3.0 и упускало 3.3.1, а это реальное уведомление <code>converse.js</code>, — а <code>=103</code> означает всю линейку 103, а не одну точку, и <code>binaryen</code> записывает так восемь уведомлений. Теперь читаются и диапазоны с крышкой, тильдой, <code>1.x</code> и дефисом, тогда как прежде запись в любой из этих форм отбрасывалась без единого слова. Проверено на всех 4696 различных диапазонах версий, которые gemnasium публикует для npm: при собственном толковании расхождений с npm было 9, при делегировании — ни одного. Затронут только npm: в Python <code>==1.0</code> — это точная версия, а не подстановочный знак, так что применение там правила npm выдумало бы находки.
- Три вещи, в которых прочтение npm верно для установки пакета и неверно для уведомления, применять не стали. Диапазон, не называющий ни одной версии — <code>*</code>, <code>x</code>, пустое поле, — при установке означает «любая версия», а в уведомлении неотличим от «это поле никто не заполнил», поэтому он отклоняется, а не превращается в находку против всех когда-либо выпущенных версий. Затесавшийся в конец <code>||</code> больше не может расширить предшествующий ему диапазон до всего. И <code>>0</code> по-прежнему означает все версии, потому что <code>pandora-doomsday</code> именно так объявляет свой вредоносный пакет, а по прочтению npm вся ветка 0.x оказалась бы чистой. Отдельно: уведомлению, чьё заявленное исправление находится на начале собственного диапазона или ниже, эта граница больше не подставляется — так получался интервал, не совпадающий ни с чем, то есть находка, которая молча перестаёт сообщать, — а правило отбрасывания такого интервала теперь общее с источником OSV, а не написанное отдельно для каждого источника, что и было причиной их первоначального расхождения.
- Тесты, которые всё это упускали, теперь порождают свои входные данные, а не перечисляют их. Каждый отдельный диапазон версий, который gemnasium публикует для npm, при каждой сборке сверяется с собственной реализацией npm, вместе с полным перебором грамматики диапазонов и всеми порядками событий диапазона в OSV. На предыдущем выпуске этот прогон падает на 28 диапазонах, тогда как десять рукописных примеров, которые он заменил, проходили все. Любое написание, которое вышестоящий источник придумает впредь, обрушит сборку при первом же импорте, а не тогда, когда кто-нибудь заметит порождённую им находку.
- Каждая строка кода, стоящего за этими находками, теперь выполняется тестами — операторы, ветви, функции и строки на 100%, без единого исключения во всём репозитории. Это прямой ответ на то, как проскочили ошибки последних выпусков: каждая была ветвью, которую ничто не выполняло, — она сообщала об успехе, не делая ничего. При закрытии последних 109 обнаружилось, что несколько из них числились недостижимыми защитными проверками, а на деле просто не были покрыты тестами, и что одно из правил покрытия месяцами ничего не проверяло, поскольку названный в нём файл давно переехал. Это правило и 500 строк исключений вокруг него заменены одним, так что непокрытый код теперь роняет сборку, а не занижает среднее.
- Закрыты и последние защитные пробелы: нечитаемая верхняя граница OSV оставляет допустимый интервал открытым, резервные границы проверяются после применения, а явная npm-граница предварительной версии вроде <code><1.2.3-0</code> сохраняет точный смысл.
Уведомления, объявлявшие уязвимой любую версию
v3.3.2 · 17 авг. 2026 г.- Уведомление, у диапазона которого нет верхней границы, совпадает со всеми версиями и делает это всегда: такую находку не снимет никакое обновление, а на странице её не отличить от действительно неисправленной уязвимости. Два уведомления по <code>xlsx</code> пришли именно в таком виде и сообщали о полностью исправленной 0.20.3 как о высокой серьёзности без доступного исправления — сразу в 11 проектах, тогда как <code>npm audit</code> корректно указывал те же два как исправленные в 0.19.3 и 0.20.2. Причина находится выше по цепочке и она намеренная: GitHub не называет исправленную версию, которую реестр не отдаёт под этим именем пакета, — SheetJS публикует 0.19.3 и новее только со своего CDN, — поэтому записывает диапазон как «всё начиная с 0», а настоящую границу помещает в отдельное поле, которое Sentinello не читал. Теперь читает. Затронуто было 15 npm-уведомлений, среди них <code>babel-traverse</code> и <code>sandbox</code>. Те 480, что действительно без исправления, по-прежнему так и сообщают, а запись, уже указавшая собственную границу, никогда не перезаписывается
- Уведомление gemnasium, оставлявшее диапазон открытым и при этом перечислявшее исправляющие версии, теперь ограничивается самой старшей из них. Диапазон без конца утверждает, что уязвимы и все будущие выпуски, — а запись, называющая исправление, не может иметь это в виду
- gemnasium записывает диапазоны версий Python как пересечения PEP 440 — <code>>=5.0,<5.8</code>, — а разборщик делил строку на токены только по пробелам, поэтому всё превращалось в один токен: нечитаемая нижняя граница и полное отсутствие верхней. Такие диапазоны не совпадают ни с чем, а не совпасть ни с чем — значит ни о чём не сообщить. В этом состоянии находились 2830 из 7159 закэшированных записей PyPI. Это была одна из трёх причин, по которым в 3.3.0 сняли Python, Go и Rust; две другие остаются открытыми, поэтому они остаются снятыми
Тот же выпуск, что и 3.3.0, но с собирающимся Docker-образом
v3.3.1 · 15 авг. 2026 г.- 3.3.0 опубликована в npm и на GitHub, но её контейнерный образ не собрался — на момент выпуска 3.3.0 не было ни в GHCR, ни в Docker Hub. Dockerfile перечисляет каждый пакет рабочего пространства, который устанавливает, и один из них — пакет сравнения версий — там никогда не значился. До этого выпуска ничто в образе его не импортировало, поэтому пропуск ни разу не проявился. С тех пор опубликован исправленный образ 3.3.0, собранный из кода приложения самой 3.3.0, так что <code>docker pull sentinello:3.3.0</code> снова работает. 3.3.1 несёт то же исправление в дереве исходников. Для CLI версия 3.3.0 уже была верной.
Только те экосистемы, которые действительно работают — и уведомления, которым можно верить
v3.3.0 · 15 авг. 2026 г.- Уведомление могло прийти пустым. Оператор получил сообщение в Telegram, объявлявшее об уязвимостях в проекте и не перечислявшее ни одной. Рассылка ограничена проектом, но выполнялась по одному разу на сканер: проход npm audit получил два ожидающих события OSV, не сопоставил ни одного и всё равно отрисовал заголовок над пустым списком. Затем он пометил оба события как доставленные — и две находки, которые он ни разу не назвал, оказались записаны как отправленные, а к доставленному событию больше никто не возвращается. Теперь событие рассылается, только если его можно описать; если нет, оно остаётся в ожидании и рассматривается снова при следующем сканировании
- Находка сообщается с худшей оценкой, которую ей дал хоть один источник, и это повышение доходило до панели, итогов по проекту и шлюза <code>--fail-on</code> в CLI — но не до порогов уведомлений. Уведомление выполнялось до подтверждения, поэтому событие получало оценку уцелевшего источника и больше не переписывалось. На реальной инстанции 135 открытых находок несли серьёзность события ниже настоящей, <strong>41 из них записывала critical как low, high или moderate</strong>. Цель, отфильтрованная по critical и high, не была бы вызвана ни по одной из них — навсегда
- Запланированные сканирования останавливались в полночь, вместо того чтобы продолжаться. «Каждые 3 часа с 07:00» запускалось в 07, 10, 13, 16, 19 и 22, а затем только в 07:00 — шесть сканирований в сутки вместо восьми, с девятичасовым слепым окном каждую ночь — при этом Настройки продолжали показывать выбранный интервал. «Каждые 6 часов с 20:00» давало одно сканирование в сутки. Теперь слоты переходят через смену суток
- <strong>Python, Go и Rust отозваны.</strong> Это не осторожность из-за шероховатостей: их сбои сообщались как «чисто». Вывод исправленной версии и упорядочивание версий работают только по semver, поэтому рекомендация OSV по Django советовала «обновиться до 3.2.23» для установленной 4.2; имена пакетов PyPI в OSV не канонизированы по PEP 503 и потому никогда не совпадали с именами резолвера; а парсер диапазонов gemnasium не умеет читать пересечения через запятую из PEP 440. Источник, который по неверным причинам отвечает «уязвимостей нет», хуже того, который не предлагается вовсе, — поэтому они полностью убраны с поверхности продукта: ни переключателя, ни обнаружения, ни загрузки. <strong>Находки, уже собранные с ними, остаются видимыми, их можно заглушить; ничего не удаляется.</strong> Экосистема npm теперь называется <strong>Node.js</strong> — это имя реально сканируемой экосистемы пакетов, а не языка
- <strong>Настройки → Источники</strong> перестроены вокруг этого. Раньше каждый источник повторял собственное объяснение рядом с собственным переключателем, а каждый источник с кэшем нёс пятистрочную панель состояния с собственной полноразмерной кнопкой «Обновить сейчас» — хотя эта кнопка ставит в очередь один общий сигнал на источник, сколько бы раз она ни появлялась. Теперь переключатели говорят только о том, включён ли источник; что каждый из них добавляет, что и откуда загружает и когда работает, переехало в одну справочную таблицу под ними, а состояние синхронизации уместилось в одну строку
- Пакеты, которые собственный lock-файл npm объявляет достижимыми из продакшена, понижались до «только разработка». Отсутствие <code>dev: true</code> в lock-файле — это утверждение npm, что пакет ДОСТИЖИМ из продакшена, и оно сильнее того, что может сказать корневой манифест. Но резолвер перекрывал его всякий раз, когда имя встречалось и в <code>devDependencies</code>, то есть ровно тогда, когда npm был прав. Измерено на 130 реальных проектах: 142 пакета понижены в 97 из них — lodash, semver, postcss, tailwindcss, @babel/runtime — из-за чего на одной инстанции семь открытых находок скрылись из фильтра «только продакшен»
- Любой пакет, закреплённый на версии вида <code>0.0.0-20180523222229-09b5706aa936</code>, не совпадал <strong>ни с одной рекомендацией</strong> — даже с открытой — и сканирование сообщало ok при нулевом числе находок. Нижняя граница <code>introduced: 0</code> сравнивалась как релиз 0.0.0, а в semver предрелиз сортируется ниже своего релиза. 330 из 19 085 сравнимых диапазонов реального кэша хранились как интервалы, которые ничем нельзя удовлетворить
- Прерванная синхронизация OSV могла удалить рекомендацию навсегда. Инкрементальный путь удалял строки рекомендации, а замену получал уже внутри try/catch, поэтому любой таймаут, 5xx или остановка стирали её целиком — а курсор всё равно продвигался, оставляя идентификатор позади навсегда. Потеря была молчаливой, доживала до следующего полного пересева и происходила в синхронизации, которая отчитывалась об успехе. Кэш <code>npx sentinello</code> точно так же истончался при каждом нестабильном запуске. Теперь оба сначала получают и только потом заменяют
- <code>--dep-type dev</code> в CLI означал «достижим из dev хоть как-нибудь», тогда как портал имеет в виду «достижим <em>только</em> из dev», поэтому пакет, достижимый из обоих, появлялся в одном представлении и отсутствовал в другом — на одной инстанции два прочтения расходятся на 177 открытых находок. Теперь CLI использует правило портала и учитывает поле <code>withdrawn</code> из OSV, прочитать которое раньше был структурно неспособен: 585 строк реального npm-кэша несут его, и все они сообщались как действующие находки
- Рекомендация gemnasium, которая сообщает, что уязвимость начинается <em>после</em> версии — <code>>1.2.8</code>, а не <code>>=1.2.8</code>, — читалась так, будто затронута и сама граничная версия. Захват пакета <code>rc</code> в 2021 году описан именно так, а 1.2.8 — его последний чистый выпуск: ровно та версия, на которой рекомендация своим же указанием по устранению советует остаться. В результате каждому проекту с установленным <code>rc</code> показывалась критическая находка о вредоносном коде без доступного исправления — против версии, которая никогда не была скомпрометирована. Теперь границы сохраняются ровно так, как их формулирует рекомендация, и ложные критические находки такого рода исчезают
- То же округление работало и в обратную сторону, скрывая настоящие находки. Рекомендация с границей <code><=2.0.0</code> сохранялась как «ниже 2.0.0», поэтому сама 2.0.0 — версия, о которой сказано яснее всего, — не сообщалась, а рекомендация, называющая ровно одну затронутую версию, превращалась в пустой интервал и отбрасывалась целиком. Ожидайте небольшое число новых находок, которые всегда были, но оставались невидимыми
- Диапазоны, записанные синтаксисом, который Sentinello не реализует, — <code>^1.0.0</code>, <code>~1.0.0</code> — сохранялись как точная версия, привязанная к буквальному тексту, и потому не могли совпасть ни с чем, пока оставались в кэше: рекомендация выглядела действующей, но сработать не могла. Такие записи теперь отклоняются, а не хранятся в неработоспособном виде; рекомендациям, у которых верхняя граница не несёт чистой исправленной версии, наконец выдаётся предложение по обновлению
- Помощник, который маскирует URL вебхука или токен бота, прежде чем тот попадёт в строку журнала, печатал короткие значения целиком. Он отклонял значения из шести символов и меньше, но затем оставлял восьмисимвольную голову и четырёхсимвольный хвост, и никто не проверял, не смыкаются ли эти две половины — так что любой секрет длиной от 7 до 12 символов возвращался полностью. Теперь он скрывает не менее восьми символов либо затирает значение целиком
Находки показывают, какие источники согласны, а отозванные рекомендации больше не сообщаются
v3.2.0 · 15 авг. 2026 г.- Когда одну и ту же уязвимость сообщают несколько баз рекомендаций, Sentinello всегда оставлял ОДНУ находку: сообщать об одном изъяне трижды лишь потому, что о нём знают три базы, — это шум. Но всё, что касалось объединённых источников, до сих пор отбрасывалось, и уязвимость, независимо подтверждённая npm audit, OSV и GitLab gemnasium, выглядела ровно так же, как та, о которой слышала лишь одна база. На реальном экземпляре это две трети всех находок. Теперь каждая находка несёт с собой остальные источники, сообщившие о ней, и их метки отображаются рядом с сохранившейся
- Находка сообщается с САМОЙ ВЫСОКОЙ серьёзностью, которую ей присвоил любой источник. Базы действительно расходятся в оценках: gemnasium вычисляет серьёзность по вектору CVSS, а npm audit берёт категорию GitHub — и для сканера действовать стоит по осторожному прочтению. Это не косметика: повышенная находка меняет категорию на панели, в итогах проекта, в барьере <code>--fail-on</code> у CLI и в порогах уведомлений. При первом сканировании после обновления некоторые счётчики сдвинутся; ничего нового не обнаружено — те же находки оцениваются осторожнее
- Там, где источники расходятся, рядом с серьёзностью находки появляется элемент управления, открывающий то, что сказал каждый источник: его собственный идентификатор рекомендации и его оценку. Он появляется только при наличии расхождения, поэтому находка, оценённая всеми одинаково, остаётся лаконичной
- OSV фиксирует отзыв в отдельном поле, а GitHub удаляет отозванные рекомендации ещё до того, как их увидит <code>npm audit</code>, но у GitLab gemnasium такого поля в схеме нет. Он отзывает рекомендацию, переписывая запись на месте: заголовок становится «False Positive», «Withdrawn Advisory: …» или «Duplicate Advisory: …», а версии, которые она называла прежде, остаются на месте. Sentinello читал эти версии и сообщал о находках, которые GitLab явно отозвал: 383 записи по JavaScript, Python, Go и Rust, включая одну, сообщавшую об <code>express</code> под заголовком «False Positive». Теперь все они отбрасываются, что заодно устраняет целый класс дублирующихся находок — 278 из 383 отозваны именно как дубликаты другой рекомендации
- Проверка сопоставляет маркеры отзыва точно, а не ищет слова где угодно в тексте, поэтому настоящая рекомендация, посвящённая ложному срабатыванию, по-прежнему сообщается: CVE-2026-39395 для Cosign с заголовком «Cosign’s verify-blob-attestation reports false positive when payload parsing fails» не затронут
- Кэш gemnasium перестраивается сам при первой синхронизации после этого обновления, и тогда отозванные рекомендации исчезают. Ничего делать не нужно: это произойдёт при ежедневной синхронизации или сразу через «Настройки → Источники → Обновить»
Диапазоны версий в рекомендациях верны в обе стороны
v3.1.1 · 14 авг. 2026 г.- Некоторые рекомендации GitLab gemnasium вообще не содержат машиночитаемого диапазона версий — 698 из 10 777 для JavaScript. Sentinello закрывал этот пробел предположением, что затронуты все версии ниже первого перечисленного исправления, но этот список не упорядочен и содержит по одному исправлению на ветку выпуска, поэтому догадка регулярно попадала не в ту ветку. protobufjs 7.6.5 сообщался как критическое удалённое выполнение кода, хотя эта ветка была исправлена в 7.5.5, а три отдельные рекомендации утверждали, что уязвимы все версии vite ниже 8.0.5. Sentinello больше не выдумывает диапазоны: он восстанавливает настоящий из той же рекомендации, опубликованной под другим идентификатором, из её собственного описания или — только если у вас включён OSV — из копии OSV, уже имеющейся на вашей машине, а если ничто из этого не отвечает, отбрасывает запись, а не строит догадки. Часть критических находок исчезнет
- OSV описывает рекомендацию, исправленную в нескольких ветках выпуска, отдельной записью на каждую ветку, а Sentinello оставлял первую и отбрасывал остальные — 1 927 уязвимых диапазонов версий только для JavaScript, и каждый из них — реальная уязвимость, ставшая невидимой. Рекомендация minimatch охватывает восемь веток, а выживала лишь одна, поэтому установленный minimatch 3.0.4 или 9.0.0 не сообщался; next и ua-parser-js теряли ветки так же. Теперь сохраняются все ветки. Появятся новые находки — эти уязвимости существовали всегда, просто были невидимы
- Оба кэша рекомендаций перестраиваются сами при первой синхронизации после этого обновления, потому что хранящиеся в них диапазоны созданы прежним кодом. Ничего делать не нужно: это произойдёт при ежедневной синхронизации или сразу через «Настройки → Источники → Обновить», если не хотите ждать
Заглушённые находки уходят с глаз долой, а база данных перестаёт расти без конца
v3.1.0 · 13 авг. 2026 г.- Заглушённая находка — это решение, которое вы уже приняли, поэтому теперь она полностью уходит со страницы проекта, а не остаётся на ней блёклой строкой. Дело не только в аккуратности: каждое число на странице — счётчик в заголовке, значки обеих вкладок, постраничная навигация, итоги по библиотекам, кнопка экспорта — считается по одним и тем же строкам, так что страница наконец согласуется с панелью, инструментами MCP и экспортом рекомендаций, которые и раньше исключали заглушённые находки. Переключатель «Показать заглушённые» возвращает их в любой момент, в том числе в проекте, где заглушены *все* находки
- Ввод в диалоговом окне больше не теряет фокус после первого же символа. Из-за этой ошибки поле «Причина» в диалоге заглушения было практически невозможно заполнить — хотя оно обязательное и остаётся единственным, что позволяет разобраться в заглушении спустя месяцы. Тот же диалог перестал наследовать выравнивание строки таблицы, из которой он открыт: именно поэтому при заглушении находки диалог получался выровненным по правому краю, а при заглушении проекта — нет
- История сканирований больше не растёт бесконечно. Ничто и никогда не удаляло записи сканирований по возрасту, поэтому проект, остававшийся на диске, бесконечно накапливал по строке на источник за каждый проход — реальный экземпляр дошёл до 2,2 ГБ меньше чем за три месяца. В «Настройках → Дополнительно» появился срок хранения, по умолчанию 90 дней, и воркер ежечасно удаляет всё, что старше, всегда сохраняя 100 последних сканирований каждого проекта. Находки, заглушения и история уведомлений не затрагиваются — только журнал сканирований. При 90 днях обновившийся экземпляр ничего не удалит на первом же проходе: очистка начнётся, только когда история действительно окажется старше этого срока или когда вы сами уменьшите его
- Основная часть этого роста — необработанный вывод `npm audit`, который целиком сохранялся при каждом успешном сканировании и не читался ничем: 98,7 % базы данных того экземпляра. Теперь сканирования записывают краткую сводку, и строка уменьшается примерно с 79 КБ до сотни байт, а жёсткое ограничение не позволит ни одному сканеру повторить это
- В MCP инструмент `get_dashboard_summary` теперь прямо сообщает, что заглушённый вами проект выпадает из его итогов, тогда как `list_projects` по-прежнему его возвращает. Они намеренно считают разные совокупности, и агент, сравнивавший их, принимал это за ошибку. `list_scans` также перестал возвращать необработанный вывод сканера по каждому сканированию, который в одном ответе мог достигать примерно 16 МБ
Загрузка gemnasium снова работает, а CLI возвращает терминал
v3.0.1 · 4 авг. 2026 г.- В 3.0.0 загрузка GitLab gemnasium падала с `HTTP 406` у всех. Встроенный fetch в Node добавляет заголовок `Sec-Fetch-Mode: cors`, который программа не вправе убрать, а GitLab отклоняет любой запрос архива репозитория с этим заголовком — так что дело никогда не было ни в вашей сети, ни в IP, ни в числе повторов. Теперь загрузка выполняется обычным HTTPS-запросом и проходит успешно
- Архив запрашивается по идентификатору коммита, а не по имени ветки: все, кто обновляется с одного и того же коммита, используют общую кэшированную копию вместо того, чтобы каждый просил GitLab собрать архив на 60 МБ. Первая загрузка, занимавшая почти семь минут, теперь завершается за секунды
- CLI заканчивал всю работу — записывал отчёт, печатал сводку — и после этого не возвращал терминал. Соединение загрузки оставалось открытым и удерживало процесс; теперь оно закрывается сразу после чтения архива
- Источник, отказавший в загрузке, больше не молчит три минуты перед сообщением. Он сообщает за секунды и в терминале предлагает повторить — повторяя только тот источник, который действительно не удался
- `--fail-on` честен в обе стороны. Он отклоняет запуск, в котором источник рекомендаций не удалось опросить, вместо того чтобы отчитаться о чистом сканировании, которого не было; и больше не заваливает запуск из-за источника, который вы сами отключили через `SENTINELLO_OSV_FEED_URL=off` или `SENTINELLO_GEMNASIUM_FEED_URL=off` и ни разу не загружали
Sentinello теперь работает вообще без портала
v3.0.0 · 3 авг. 2026 г.- Сканеры выходят как CLI в npm. `npx sentinello` обходит папку, находит все проекты внутри, сверяет их с npm audit, OSV и GitLab gemnasium и пишет markdown-сводку с приложенным промптом по устранению — без установки, без аккаунта, без базы данных, и ничего из вашего кода не покидает машину
- В конвейере на stdout попадает только сводка, поэтому `npx sentinello | claude -p "$(cat -)"` передаёт агенту полный список работ, ничем не повредив документ
- Первый запуск больше не теряет источник gemnasium из-за отклонённой загрузки. GitLab отклоняет свой архив на минуту-две подряд, а прежние повторы сдавались через тринадцать секунд; теперь CLI дожидается окончания, объясняет, почему ждёт, и принимает `--feed-wait`, если три минуты по умолчанию вам не подходят
- Обе оценки размера загрузки измерены, а не угаданы: npm-экспорт OSV указан как 204 МБ вместо 196, а архив gemnasium — как 52 МБ вместо 80. В запросе подтверждения оценка помечается тильдой, чтобы её нельзя было принять за размер, сообщённый сервером
- Значение, похожее на флаг, теперь отклоняется, а не понимается буквально: `--out --` раньше писал сводку в файл с именем `--` внутри вашего проекта и рапортовал об успехе
- Панель «Что нового» больше не уходит за нижний край окна, когда в релизе много изменений
Документ с рекомендациями действительно доходит — и считает верно
v2.6.0 · 29 июл. 2026 г.- get_project_advisory теперь возвращает сам документ. Раньше подключённые клиенты получали только метаданные — имя файла и количество — но не документ, хотя инструмент описывал его как полный рабочий список
- Экспорт рекомендаций теперь содержит одну запись на каждую отдельную рекомендацию с объединёнными источниками, а не одну на строку сканера: уязвимость, о которой сообщают и npm audit, и OSV, становится единой рабочей задачей с обоими идентификаторами, а не двумя почти одинаковыми. Это касается и кнопки «Скачать .md» в портале, а количество теперь совпадает с панелью
- Проект, который не помещается в один ответ MCP, теперь разбивается на страницы: документ сообщает, что он неполный, и указывает точный следующий вызов для получения остального, вместо того чтобы молча обрываться там, где агент счёл бы остаток чистым
- У каждого параметра каждого инструмента MCP появилось описание, а новый инструмент list_mutes выдаёт идентификаторы отключений, нужные для unmute — раньше их можно было узнать, только создав отключение в той же сессии
- Исправлен пробел в подсчёте уровней риска: находка с уровнем вне пяти известных значений учитывалась как находка, но не попадала ни в одну категорию, поэтому проект с единственной такой находкой выглядел полностью чистым
Экспорт рекомендаций прямо через MCP
v2.5.0 · 28 июл. 2026 г.- Подключённые MCP-клиенты могут получить полный Markdown-отчёт проекта новым инструментом get_project_advisory — тот же документ, что и кнопка «Скачать .md» в портале, без копирования из браузера
- Заглушённые находки больше не попадают в экспорт рекомендаций проекта, поэтому агент никогда не получит работу, риск которой вы уже приняли
- Примечание: поскольку отчёт содержит ваш промпт экспорта, MCP-клиент теперь может прочитать то, что вы написали в Настройки → Экспорт
Всплывающие панели без обрезки и более строгий промпт экспорта
v2.4.3 · 26 июл. 2026 г.- Выпадающие списки, всплывающая панель пути зависимости и меню экспорта рекомендаций больше не обрезаются таблицей или диалогом, в котором они находятся, — они отрисовываются поверх страницы и раскрываются вверх, когда снизу не хватает места
- Стандартный промпт экспорта рекомендаций теперь требует от агента сначала составить план и только потом что-то править, группировать находки, закрывающиеся одним исправлением, и описывать влияние каждого изменения версии на код; цель — ноль находок, но обходные пути к фальшивому нулю запрещены: заглушение, расширение диапазонов или сужение области сканирования, а действительно нерешаемое попадает в датированную таблицу остатков
Ветка в отдельной колонке
v2.4.2 · 25 июл. 2026 г.- Ветка git, на которой сканировался проект, теперь занимает отдельную колонку в списке проектов — обычный текст, без иконки — вместо строки под названием проекта
Корректное завершение работы
v2.4.1 · 25 июл. 2026 г.- Перезапуск контейнера больше не обрывает сканирование на середине записи, а воркер запускается сразу, а не после ~30 секунд повторных попыток
- Задайте stop_grace_period: 60s (или --stop-timeout 60) в compose-файле, чтобы дать ему запас, — README и документация по Docker теперь это описывают
Полиглотное сканирование — к npm добавились Python, Go и Rust
v2.4.0 · 25 июл. 2026 г.- Sentinello теперь сканирует проекты на Python, Go и Rust наряду с npm — файлы блокировок разбираются полностью офлайн, а каждый проект сообщает своё покрытие сканирования (полное, частичное или непроверяемое), поэтому пробелы видны, а не остаются незамеченными
- База gemnasium от GitLab присоединяется к npm audit и OSV как офлайн-источник рекомендаций с дедупликацией по псевдонимам CVE/GHSA; раздел Настройки → Источники стал матрицей «Языки × Источники» с областью уведомлений для каждой ячейки, а сам npm audit теперь можно отключить, пока активен хотя бы один источник
- Находки теперь фиксируют ветку git, из которой они получены, — она видна в списке проектов, в заголовке проекта и в каждом уведомлении
- В строках проектов появились собственные действия — сканировать сейчас, скопировать или скачать рекомендацию, заглушить или снять заглушение и изменить теги, — поэтому для разбора больше не нужно заходить в каждый проект
- Панель проектов ускорилась с ~3,3 с до ~0,03 с, а при переходах теперь показываются состояния загрузки вместо подвисшей страницы
- Безопасность: устранено 25 рекомендаций по зависимостям, включая CVE в libvips, которые реально действовали в оптимизаторе изображений портала, и девять рекомендаций Next.js, затрагивавших поставляемый портал
- Стандартный промпт экспорта рекомендаций теперь учитывает минимальный возраст релиза, проверку файла блокировки и устаревшие override
Более простая настройка MCP — без переменных окружения
v2.3.0 · 9 июн. 2026 г.- Теперь MCP настраивается полностью в «Настройки → MCP»: сгенерируйте токен, чтобы включить эндпойнт /api/mcp, очистите его, чтобы выключить — переменные окружения SENTINELLO_MCP_ENABLED и SENTINELLO_MCP_API_TOKEN удалены (существующий токен из окружения импортируется один раз при обновлении)
- Готовые к вставке фрагменты подключения для Claude Code, Codex, Cursor и Claude Desktop, уже заполненные вашим токеном
- Когда SENTINELLO_PORTAL_BASE_URL задана в окружении, она отображается только для чтения в «Настройки → Дополнительно», поскольку остаётся приоритетной и повторно применяется при каждом запуске
Меньше ложных срабатываний и самоочищающиеся находки
v2.2.0 · 9 июн. 2026 г.- Оповещения о вредоносном ПО теперь сопоставляются с точной затронутой версией — чистая или уже исправленная версия некогда скомпрометированного пакета больше не помечается
- Дублирующиеся находки теперь устраняются сами при следующем сканировании, поэтому старые или осиротевшие записи удаляются автоматически
- Метки production и development теперь вычисляются единым согласованным способом по всем источникам (npm и OSV)
Более чистый заголовок проекта и единообразные фильтры
v2.1.0 · 6 июн. 2026 г.- Упрощённый заголовок проекта — переименование рядом с названием, отключение и теги в виде иконок
- Фильтрация находок по источнику (npm / OSV) через новый выпадающий список рядом с фильтром типа зависимости
- Единообразные выпадающие списки по всему приложению, с поиском по вводу для длинных списков, например часовых поясов
Более понятные инструкции по обновлению
v2.0.1 · 4 июн. 2026 г.- Расширенные шаги обновления для несовместимых изменений 2.0
- В README указана привязка порта только к localhost
Сканирование из нескольких источников и усиленная, безопасная по умолчанию установка
v2.0.0 · 4 июн. 2026 г.- OSV как необязательный второй источник (Настройки → Источники, по умолчанию выключено) с обнаружением вредоносных пакетов, сверяемый с публичной базой данных OSV в локальном кэше
- Результаты теперь объединяются между источниками — одна строка на уязвимость, каждый источник помечен, лучшее доступное исправление и объединение путей зависимостей, с фильтром по источнику и всплывающим окном пути зависимости
- Усиление безопасности: эндпойнт MCP по умолчанию выключен и требует токен, доставка вебхуков защищена от SSRF, необязательный вход в портал, и контейнер запускается от непривилегированного пользователя
- Настройки теперь — раздел верхнего уровня с боковой панелью и страницей профиля
Интеграция MCP и новинки
v1.4.0 · 29 мая 2026 г.- MCP-сервер по адресу /api/mcp для Claude Desktop, Cursor и других клиентов
- Новый раздел «Настройки → MCP» с URL сервера и управлением токенами
- Значок новинок и история примечаний к выпускам
Исправление версии в подвале
v1.3.1 · 28 мая 2026 г.- Текущая версия корректно отображается в подвале
Улучшения уведомлений
v1.3.0 · 28 мая 2026 г.- Фильтрация уведомлений по среде
- Более простая форма редактирования получателей
- Дублирование существующего получателя уведомлений
Страницы проектов и библиотек
v1.2.0 · 24 мая 2026 г.- Главный экран разделён на отдельные страницы проектов и библиотек
Живая перезагрузка расписания
v1.1.2 · 24 мая 2026 г.- Воркер перезагружает расписание сканирования сразу после сохранения изменений в портале
Более безопасное удаление и понятный баннер обновления
v1.1.0 · 23 мая 2026 г.- Подтверждение перед удалением корней и получателей уведомлений
- Уведомление об обновлении перенесено в закрываемый баннер сверху
- Воркер удаляет устаревшие корни, когда их монтирование исчезает
Исправления точности сканера
v1.0.1 · 23 мая 2026 г.- Отбрасывает результаты, чья установленная версия фактически не входит в уязвимый диапазон
- Позволяет удалить получателя уведомлений с историей отправок
Первый релиз с открытым исходным кодом
v1.0.0 · 23 мая 2026 г.- Первый публичный выпуск Sentinello
Дорожная карта
Сегодня Sentinello следит за вашими зависимостями на нескольких языках. Вот куда он движется — и что вы можете запросить.
Умнее приоритизация
ЗапланированоРанжируйте находки по эксплуатируемости и по тому, достижим ли уязвимый код, — сначала разбирайте главное.
Больше интеграций
ЗапланированоБольше каналов уведомлений и способов подключить Sentinello к инструментам, которыми ваша команда уже пользуется.
Статический анализ (SAST)
ЗапланированоВыявляйте рискованные паттерны в вашем собственном коде, а не только известные CVE в зависимостях.
Сканирование секретов и лицензий
ЗапланированоОтмечайте закоммиченные секреты и проблемы с лицензиями в том же портфеле, в той же очереди.
Расскажите, что бы вы интегрировали или просканировали дальше — откройте issue на GitHub и помогите сформировать дорожную карту.