
Автоматизированный уровень безопасности зависимостей для ИИ-помощников по кодированию, который проверяет пакеты на наличие CVE, typosquats, заброшенность, проблемы с возрастом версий и целостность хешей в экосистемах npm, PyPI, RubyGems, Maven, Go и Rust.
Когда ИИ-ассистенты по написанию кода, такие как Claude, добавляют пакеты в ваш проект, они часто выбирают ту версию, которая звучит подходяще — не проверяя, есть ли у неё известные уязвимости безопасности, поддерживается ли пакет по-прежнему активно, или не является ли имя опечаткой от вредоносного двойника.
safer-dependencies — это уровень безопасности для Claude Code: он находится между Claude и вашими файлами манифестов и автоматически выполняет свои проверки безопасности: установки с уязвимостями отклоняются до их запуска, а рискованная версия, записанная в манифест, исправляется на диске сразу после записи. Он обнаруживает и исправляет рискованные зависимости — CVE, typosquatting, заброшенные пакеты и проблемы с возрастом версий, а также период охлаждения для совершенно новых релизов — в npm, PyPI, RubyGems, Maven, Go, Rust и PHP (Composer). См. CAPABILITIES.md для точного описания того, что покрывается, а что нет.
Новичок? GETTING-STARTED.md проведёт вас от нуля до рабочей установки примерно за пять минут.
Безопасность и конфиденциальность: см. SECURITY.md (раскрытие уязвимостей), PRIVACY.md (исходящие данные, отсутствие телеметрии) и CAPABILITIES.md (от чего инструмент защищает, а от чего нет).
Лицензия (исходный код доступен — НЕ OSI «открытый исходный код»): Бесплатно для использования и модификации в своих целях, включая коммерческое использование внутри компании и создание продуктов, которые вы продаёте. Отдельная платная лицензия требуется для монетизации самого программного обеспечения — его продажи, включения в продукт или сервис, который продаётся, или предоставления его функциональности третьим лицам за плату (включая хостинг/SaaS/API). Распространение и производные работы должны сохранять лицензию и указывать этот проект. См. (Раздел 4 об ограничении коммерческого использования); запросы на коммерческую лицензию через .
GETTING-STARTED.md проведёт вас от нуля до рабочей установки примерно за пять минут — предварительные требования, интерактивная установка и проверка. Для полного справочника по установке (глобальная/проектная/ручная установка, особенности Windows, список разрешённых разрешений, обновление и удаление) см. INSTALLATION.md.
Повседневное использование: после установки хуков ничего запускать не нужно — safer-dependencies работает автоматически в фоновом режиме. Когда Claude добавляет или устанавливает пакеты, он помечает рискованные зависимости и обновляет уязвимые версии до безопасной на месте — и блокирует установку с известной уязвимостью до её запуска — так что небезопасные пакеты обнаруживаются и исправляются без необходимости вас просить. Вы всё равно можете вызывать его напрямую в любое время: «безопасен ли [email protected]?», «проверь настройку safer-dependencies» или «покажи статистику safer-dependencies».
Когда Claude собирается добавить пакет в ваш проект, safer-dependencies перехватывает действие и выполняет 5 проверок:
requirements.txt с привязками --hash=sha256:... объявленный хэш проверяется на соответствие опубликованным хэшам PyPI; несовпадение выдаёт WARNINGpaperclip, request, pycrypto, github.com/dgrijalva/jwt-go) немедленно жёстко блокируются с предложенной заменой; пакеты без стабильного релиза в течение 2+ лет получают рекомендательное предупреждение STALE:. Жёстко заблокированные пакеты удаляются из манифеста, и Claude спросит, как действовать дальше; пакеты только с пометкой устаревших остаются на месте.Если обнаружены проблемы, Claude выдаёт предупреждения и может отступить к более безопасной версии. Все проверки записываются в ~/.claude/safer-dependencies-audit-YYYY-MM.log (один файл на календарный месяц).
Навык срабатывает автоматически, когда Claude:
Операции с манифестом / установкой
package.json, requirements.txt, Gemfile, pom.xml, build.gradle, Cargo.toml, go.mod или любом другом поддерживаемом манифестеimport, require или use для пакета, ещё не объявленного в манифестеnpm install, bundle install, poetry install, uv sync, go mod tidy и т. д.) — Pre-Install проверяет аргументы команды, Post-Install проверяет полученный lock-файлDockerfile или CI-пайплайн (.github/workflows/*.yml и т. д.), содержащие шаги установки с закреплёнными версиями через менеджер пакетовВопросы выбора и рекомендаций
Выражения намерения использовать (до добавления)
Вопросы о здоровье и доверии к пакетам
Команды скаффолдинга
npx create-react-app, npm create vite@latest, django-admin startproject, rails new, cargo new + cargo add, «создай новый проект FastAPI»Неявные добавления пакетов (запросы функций, подразумевающие новую зависимость)
Миграция и перенос
Он не срабатывает для:
os, fs, java.util.* и т. д.)Это набор навык + хуки, а не один файл навыка. Полная установка разворачивает следующие компоненты:
| Файл | Роль |
|---|---|
skills/safer-dependencies.md | Навык (SKILL.md после установки). Описывает процедуры аудита и включает режим управления для установки/статистики. |
skills/safer-dependencies-shim.sh | Хук PostToolUse:Write/Edit — проверяет записи манифестов и lock-файлов и автоматически исправляет уязвимые версии на месте (режим перехвата). |
skills/safer-dependencies-pretooluse-bash.sh | Хук PreToolUse:Bash — предварительная OSV-проверка команд установки через менеджер пакетов; отклоняет уязвимые конкретные версии до запуска установки (режим перед установкой). |
skills/safer-dependencies-posttooluse-bash.sh | Хук PostToolUse:Bash — проверка после выполнения Bash-команд; выявляет транзитивные CVE в только что записанных lock-файлах, манифестах, отредактированных через sed/jq/скрипты, и в разрешённом окружении обычного pip install (режим после установки). |
skills/safer-dependencies-pretooluse-agent.sh + skills/safer-dependencies-posttooluse-agent.sh | Пара хуков PreToolUse:Agent + PostToolUse:Agent — закрывает пробел покрытия субагентов. Режимы 2–4 срабатывают только для вызовов инструментов корневой сессии, поэтому любой манифест, записанный субагентом, обходит их. Post-Agent проверяет то, что записал субагент, после каждого возврата вызова инструмента Agent (режим после агента). |
skills/scripts/ | Общая библиотека Python (safedep/) и отдельные скрипты-резолверы, используемые всеми хуками. |
skills/scripts/safer_dependencies_manager.py | Модуль управления для интерактивной установки, статистики использования и проверки настройки. |
Одного файла навыка недостаточно — без хуков автоматический вызов зависит от того, решит ли Claude обратиться к навыку. Установите все пять компонентов для полного покрытия; многие навыки и слэш-команды внутренне отправляют субагентов, поэтому пара Post-Agent важна, даже если вы никогда явно не запускаете субагента. (См. FAQ.md о том, почему навык сам по себе не может гарантировать покрытие.)
| Экосистема | Манифест | Lock-файл |
|---|---|---|
| npm | package.json | package-lock.json, yarn.lock, pnpm-lock.yaml |
| PyPI | requirements.txt, pyproject.toml, Pipfile, setup.py, setup.cfg | Pipfile.lock, poetry.lock, uv.lock |
| RubyGems | Gemfile, *.gemspec | Gemfile.lock |
| Maven | pom.xml, build.gradle, libs.versions.toml | -- |
| Go | go.mod | go.sum |
| Rust | Cargo.toml | Cargo.lock |
| PHP (Composer) | composer.json | composer.lock |
Новичок в проекте? Начните с GETTING-STARTED.md. Краткая версия:```bash git clone https://github.com/robert-auger/safer-dependencies /tmp/safer-dependencies python3 /tmp/safer-dependencies/skills/scripts/safer_dependencies_manager.py interactive_install
Установщик запрашивает область действия (глобальную или для проекта) и то, какие хуки включить, после чего записывает `settings.json` за вас — как записи хуков, так **и** список разрешений, который позволяет проверочным командам навыка выполняться без запроса на одобрение при каждой аудиторской проверке.
Всё остальное, связанное с установкой, описано в **[INSTALLATION.md](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md)** — единственном справочнике по механике установки: ручная установка файл за файлом (глобальная и на уровне проекта), особенности Windows, хуки Post-Agent, [список разрешений](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#permissions-allowlist), проверка настройки, обновление, привязка к тегу релиза и удаление.
После установки повседневное управление осуществляется через естественный язык в Claude — `install safer-dependencies` (повторный запуск / изменение хуков), `show safer-dependencies stats`, `check safer-dependencies setup` — или через меню `/safer-dependencies`. Обновление также выполняется в рамках сессии: `/safer-dependencies update` применяет последний релиз (`update --check` для пробного запуска, `update --rollback` для отката); модель доверия описана в [INSTALLATION.md](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#in-session-self-updater-safer-dependencies-update).
> **Примечание о платформах:** поддерживаются macOS, Linux и Windows. Для Windows требуется Git for Windows (предоставляет bash) и Python 3 в `PATH` — WSL не нужен. Практическое тестирование на данный момент сосредоточено на **macOS и Windows**; поддержка Linux проверяется автоматической матрицей CI.
### Конфигурация
После установки можно настроить две вещи:
- **Список разрешений** — заранее одобряет проверочные команды навыка, доступные только для чтения (правила `npm audit` / `bundle audit` в точной форме и собственные скрипты-резолверы навыка), чтобы аудиты выполнялись без запроса на одобрение каждый раз; `curl` никогда не одобряется заранее, а `npm view` / `pip-audit` включаются по желанию через профиль Convenience. Интерактивный установщик записывает основные записи за вас; при ручной установке полный блок добавляется вручную. Полный блок и обоснование: [INSTALLATION.md → Permissions allowlist](https://github.com/robert-auger/safer-dependencies/blob/main/INSTALLATION.md#permissions-allowlist).
- **Политика безопасности** — окно/режим остывания по возрасту релиза и уровень `off`/`warn`/`block` для каждого типа проверки, редактируется через `/safer-dependencies config` и хранится в `~/.config/safer-dependencies/config.toml`. Схема и семантика уровней: [`skills/references/configuration.md`](https://github.com/robert-auger/safer-dependencies/blob/main/skills/references/configuration.md).
### Изменение периода остывания
Период остывания (в конфиге называется **cooloff**) — это минимальный возраст релиза, которого тот должен достичь, прежде чем навык его выберет — по умолчанию **7 дней**. Чтобы изменить его, обратитесь к Claude или выполните команду конфигурации напрямую:```
/safer-dependencies config set cooloff.days 14 # require releases to be 14+ days old
/safer-dependencies config set cooloff.mode block # gate strength: off | warn | block (default: warn)
/safer-dependencies config unset cooloff.days # revert to the 7-day default
/safer-dependencies config # show effective values and where each comes from
Те же глаголы работают и вне сеанса Claude:```bash python3 skills/scripts/safer_dependencies_manager.py config set cooloff.days 14
Настройка сохраняется в `~/.config/safer-dependencies/config.toml` (раздел `[cooloff]`); переменные окружения `SAFE_DEP_COOLOFF_DAYS` и `SAFE_DEP_COOLOFF_MODE` переопределяют файл для текущего сеанса. Три важных аспекта поведения: `mode = "off"` полностью убирает фильтр по возрасту из выбора версий; перезапись, вызванная CVE, обходит это ограничение, поэтому исправление безопасности никогда не задерживается из-за того, что оно слишком новое; и это ограничение распространяется на npm, PyPI, RubyGems и crates.io — Maven и Go намеренно не ограничиваются. Полная семантика: [`skills/references/configuration.md`](https://github.com/robert-auger/safer-dependencies/blob/main/skills/references/configuration.md).
## Уровни предупреждений
| Уровень | Значение | Пример |
|-------|---------|---------|
| CRITICAL | Остановиться и спросить пользователя | Обнаружен typosquat, подделанная подпись |
| HIGH | Предупредить и продолжить | Известная CVE, пакет младше 30 дней |
| MEDIUM | Предупредить и продолжить | Версия младше 7 дней, отсутствует подпись |
| LOW | Предупредить и продолжить | Неподписанный Ruby gem (ожидаемо) |
## Как это работает
Навык работает в пяти режимах (кратко описаны ниже; подробное обоснование архитектуры находится в `skills/safer-dependencies.md`):
### Обычный режим (вручную)
Когда Claude собирается написать `import`, добавить пакет в манифест или обновить lock-файл, навык запускается встроенно в вашем сеансе:
1. Запрашивает реестр пакетов для стабильных версий
2. Автоматически выбирает самую новую версию, опубликованную 7+ дней назад (детерминированно — без суждений LLM)
3. Проверяет известные уязвимости с помощью инструментов экосистемы и API OSV
4. Проверяет подписи пакетов, где это доступно
5. Выдаёт предупреждения при обнаружении проблем, фиксирует точную версию
6. Записывает результат в журнал аудита
Выбор версии выполняется автономными Python-скриптами, входящими в состав навыка, а не LLM, интерпретирующим правила. Команда выводит `SELECTED: <version>`, и Claude использует именно эту версию.
### Режим перехвата (автоматический)
Настройте `.claude/settings.json` с хуком `PostToolUse`, чтобы включить автоматическую, прозрачную проверку пакетов:
1. Claude записывает файл манифеста (например, `package.json`) с изначально запрошенной версией — файл попадает на диск
2. Хук `PostToolUse` срабатывает сразу после завершения записи и вызывает `safer-dependencies-shim.sh`
3. Шим читает файл, разбирает объявленные пакеты и выполняет все проверки безопасности (typosquat, заброшенность, CVE, устаревание, хэш-пиннинг)
4. Если требуются исправления, шим **перезаписывает манифест на месте** безопасными версиями (или удаляет записи, для которых нет безопасной версии)
5. Шим выводит сигналы (`UPDATED:`, `BLOCKED:`, `WARNING:`, `STALE:`, `MAJOR-UPDATE-CONFIRM:`, `REFACTOR-REQUIRED:`, `REGRESSION:`, `TYPOSQUAT-CONFIRM:`, `VERIFY:`, `CLEAN:`) через `hookSpecificOutput.additionalContext` в stdout. `REGRESSION:` предшествует `MAJOR-UPDATE-CONFIRM:`, когда журнал аудита показывает, что та же пара (файл, пакет) ранее уже была исправлена до той же безопасной цели — то есть субагент или устаревший план повторно ввёл версию с известной уязвимостью, и оркестратор должен восстановить ранее одобренную версию, а не принимать новое решение о мажорном обновлении.
6. Claude получает эти сигналы как системное напоминание и выполняет последующую работу (поиск затронутых импортов, запуск тестов, рефакторинг для критических изменений)
**Примечание к дизайну — Форма C (корректировка после записи):** хук НЕ блокирует запись. Каждая уязвимая версия сначала попадает на диск, а затем автоматически исправляется в том же цикле использования инструмента. Это осознанный выбор в пользу блокирующего дизайна `PreToolUse` — см. [FAQ.md](https://github.com/robert-auger/safer-dependencies/blob/main/FAQ.md#why-posttooluse-post-write-corrective-instead-of-pretooluse-pre-write-blocking-for-the-manifest-path) о компромиссах.
**Пример сигнала:**```
UPDATED: aiohttp 3.8.5 → 3.9.0 (HIGH: 33 CVEs fixed)
Родительский агент использует эти сигналы для выявления затронутого кода и его рефакторинга по мере необходимости.
Настройте .claude/settings.json с хуком PreToolUse:Bash, чтобы включить
предварительную проверку команд установки пакетного менеджера. Это дополняет
(но не заменяет) режим перехвата — вместе они образуют многоуровневую защиту.
npm install [email protected])PreToolUse срабатывает до выполнения вызова и запускает
safer-dependencies-pretooluse-bash.shgit status / ls / npm test несут
незначительные издержки на горячем путиnpm/pnpm/yarn
install/i/add) помощник разбивает команду на токены через shlex, извлекает каждый
аргумент pkg@version и отправляет POST-запрос в OSVpermissionDecision: "deny" с идентификатором GHSA для каждой находки + CVSS +
кратким описанием, а также подсказкой вызвать навык safer-dependenciesЗачем это нужно в дополнение к режиму перехвата: пост-записывающий шим
не видит Bash. npm install [email protected] выполняется до конца (и
postinstall-скрипты запускаются) до того, как сработает аудит; npm install -g typosquat-pkg вообще не записывает манифест проекта. Режим предварительной установки
структурно закрывает эти пробелы.
Режим предварительной установки видит только то, что пользователь ввёл (аргументы pkg@version в
командной строке). Он не видит транзитивное дерево, которое резолвер фактически
установит. Режим после установки (ниже) проверяет lockfile после
завершения установки — эти два режима дополняют друг друга, а не дублируют.
Область применения: CLI пакетных менеджеров, охваченные здесь, покрывают пять экосистем
(npm/pnpm/yarn/bun/npx/deno, pip/pip3/pipx/pipenv/uv/uvx/poetry, gem/bundle,
go, cargo), плюс Maven через режим перехвата (зависимости Maven обычно
объявляются в pom.xml/build.gradle, а не добавляются через CLI-команду).
Известный пробел: CLI Maven поддерживает прямую загрузку через
mvn dependency:get -Dartifact=group:art:versionиmvn dependency:copy. Этот хук пока не распознаёт такие вызовы. Если вы используете их регулярно, существующий пост-записывающий шим всё равно перехватит всё, что попадёт в ваш манифест, но защита до загрузки применяется только к экосистемам, перечисленным выше. Отслеживается как последующая задача.
Распознаваемый синтаксис по экосистемам:
| PM | Глаголы | Синтаксис конкретной версии |
|---|---|---|
npm, pnpm, yarn, bun | install, i, add (плюс yarn/pnpm dlx, bun x, yarn create) | [email protected], @scope/[email protected] |
npx | (без глагола — пакет является первой позиционной позицией) | [email protected] |
deno | add, install | npm:[email protected] (спецификации с префиксом npm) |
pip, pip3, pipx, pipenv, uv, uvx, poetry | install (pip/pip3/pipx/pipenv) / add (uv/poetry) / без глагола (uvx) | pkg==1.2.3 (дополнения pkg[extra]==X также обрабатываются) |
gem, bundle | install (gem) / add | -v 1.2.3, --version 1.2.3, --version=1.2.3 (отдельный флаг) |
go | get, install | [email protected] (обязательно с префиксом v согласно модулям Go) |
cargo | add, install | [email protected] |
Диапазонные версии (npm ^4.17, pip >=, poetry ^/~, Go @latest) и
неуказанные версии передаются в режим перехвата после установки —
пост-записывающий шим проверяет всё, что выберет резолвер. Автоматическая перезапись на
безопасную версию запланирована как последующая задача.
Режим отказа: отказ-открытый. Любая ошибка (отсутствие Python, сбой сети, некорректный ввод) завершается кодом 0 без вывода, позволяя bash продолжить работу. Режим перехвата всё равно запускается после установки, поэтому сбой предварительной проверки плавно деградирует до существующей защиты.
Пример отказа:``` safer-dependencies pre-flight audit blocked this install. Vulnerable pinned version(s) detected:
### Режим после установки (Bash-хук)
Настройте `.claude/settings.json` с хуком `PostToolUse:Bash`, чтобы включить
пост-проверку после выполнения Bash-команд. Он запускает **три независимых сканирования**
относительно `cwd` команды, каждое из которых закрывает пробел, который другие хуки не могут охватить:
- **Скан A — lock-файлы.** После успешной команды установки (`npm install`,
`bundle install`, `poetry install`, `uv sync`, `go mod tidy` и т.д.) проверяет
недавно изменённые lock-файлы (`package-lock.json`, `Gemfile.lock`,
`poetry.lock`, `uv.lock`, `go.sum`, `yarn.lock`, `pnpm-lock.yaml`,
`Pipfile.lock`). Это закрывает **пробел транзитивных CVE**, который Pre-Install
не видит: пользователь ввёл `pkg@version`, но резолвер мог подтянуть
десятки транзитивных зависимостей, которые никто не называл.
- **Скан B — манифесты.** После любой Bash-команды, *не* входящей в денай-лист
только для чтения (`ls`, `cat`, `git status`, …), проверяет недавно изменённые манифесты.
Это **единственный** запасной вариант для правок манифестов, сделанных через `sed -i`, `jq` или
скрипт — они обходят инструмент `Write`/`Edit`, на который завязан Intercept Mode.
- **Скан C — разрешённое окружение.** Обычный `pip install` /
`pip install -r requirements.txt` не записывает lock-файл, поэтому Скан A никогда не видит
разрешённое дерево. После установки через pip Скан C повторно вызывает тот же
pip с read-only `list --format=json` и проверяет через OSV всё разрешённое
окружение (прямые + транзитивные зависимости).
Как выполняется скан:
1. Claude выполняет вызов инструмента Bash
2. Хук `PostToolUse` срабатывает *после* завершения команды и вызывает
`safer-dependencies-posttooluse-bash.sh`
3. Чистый bash-ранний фильтр короткозамыкает команды, которые не соответствуют ни одному условию скана, за
~115 мс (та же конвенция быстрого пути, что и в Pre-Install), поэтому `ls` / `git` / `cat`
несут незначительные накладные расходы
4. Каждый скан обходит `cwd` с помощью `find -maxdepth 5` (покрывает структуры монорепозиториев;
исключает `node_modules`, `.git`, `.venv`, `venv`) в поисках файлов, изменённых в течение
последних 60 с — переопределяется через `SAFE_DEP_POSTINSTALL_MTIME_WINDOW`
5. Для каждого недавно изменённого файла (Скан A/B) хук формирует синтетический
payload `PostToolUse:Write` и передаёт его в существующий шим — аудиторы lock-файлов
и манифестов шима работают без изменений, без дублирования логики
6. Сигналы по каждому файлу объединяются и выводятся как один JSON `hookSpecificOutput`
родительскому агенту
**Что он ловит, чего не ловит Pre-Install:** транзитивные уязвимости.
Чисто выглядящий `bundle install` может подтянуть `[email protected]` (CVE-2025-27610)
как транзитивную зависимость `sinatra` — пользователь никогда не вводил `rack`, поэтому
Pre-Install не может это увидеть, но Post-Install читает разрешённый
`Gemfile.lock` и сообщает о CVE.
**Область действия:** Скан A не переписывает разрешённые версии — контракт
автоисправления применяется только к манифестам, которые Claude написал напрямую. Для транзитивных CVE
исправление обычно заключается в «обновлении прямой зависимости, которой принадлежит транзитивная», что
требует человеческого суждения. Скан B *выполняет* автоисправление, поскольку он проверяет манифесты
через тот же путь шима, что и Intercept Mode. Скан A пропускается, когда уровень проверки
`transitive` установлен в `off` (`config set checks.transitive off`).
**Режим отказа:** fail-open, как и другие хуки. Любая ошибка (отсутствующий
шим, некорректный payload, недоступный Python) завершается кодом 0 молча.
**Пример WARNING:**```
WARNING: [email protected] in lock file has GHSA-29mw-wpgm-hmr9, GHSA-35jh-r3h4-6jhm
Четыре режима выше срабатывают только для вызовов инструментов корневой сессии. Когда корневая
сессия отправляет субагента (через инструмент Agent — многие навыки и слэш-
команды делают это внутренне), вызовы Write/Edit/Bash субагента обходят все
эти режимы. Режим после агента — это реактивная страховочная сеть для этого пробела.
PreToolUse:Agent (safer-dependencies-pretooluse-agent.sh) запускается
непосредственно перед каждой отправкой агента и создаёт файл-маркер в
/tmp/.safer-deps-agent-<PPID>-<session_id>.sentinel (с откатом к имени
только с PPID, когда идентификатор сессии недоступен)PostToolUse:Agent (safer-dependencies-posttooluse-agent.sh) запускается
после возврата вызова агента, находит с помощью find каждый манифест и файл блокировки новее
маркера и проверяет каждый через тот же путь шимаadditionalContext для следующего хода корневой сессии; маркер
удаляетсяВложенные субагенты покрываются автоматически — PostToolUse:Agent корневой сессии
срабатывает только после того, как вся работа внешнего агента (включая всё, что он
отправил) окажется на диске. Единственный пробел — глобальная установка, которая не записывает
манифест или файл блокировки (npm install -g …): сканировать нечего. Как и
другие хуки, он завершается открыто — любая ошибка (отсутствующий маркер, отсутствующий
шим, нечитаемая полезная нагрузка) молча выходит с кодом 0. Полное обоснование дизайна находится в
skills/safer-dependencies.md.
Каждая проверка записывается в ~/.claude/safer-dependencies-audit-YYYY-MM.log (один файл на календарный месяц, где YYYY-MM — год-месяц по UTC) как одна строка JSON. Переопределите полный путь с помощью переменной окружения SAFE_DEP_AUDIT_LOG (при её установке суффикс даты не добавляется). Файлы также ротируются по размеру, когда превышают SAFE_DEP_LOG_MAX_BYTES (по умолчанию 10 МиБ; установите 0 для отключения). Установите SAFE_DEP_MODEL, чтобы переопределить значение модели, записываемое в source.model в каждой записи — полезно для A/B-сравнений между версиями моделей.
Все пять режимов добавляют записи в один и тот же файл. Каждая запись содержит блок source (схема 2.2), определяющий, какой компонент её записал:
source.component | Кем записано | Триггер |
|---|---|---|
shim.posttooluse | shim.sh | Запись манифеста или файла блокировки (режим перехвата, отправка после установки) |
shim.install_error | shim.sh | Сбой установки при предварительной проверке шима |
bash.pretooluse | pretooluse-bash.sh | Команда установки Bash (режим перед установкой) |
bash.posttooluse | posttooluse-bash.sh | Сам хук Bash после установки, когда он завершается открыто до достижения шима |
agent.pretooluse | pretooluse-agent.sh | Зарезервировано для событий открытого завершения перед агентом (сам хук в настоящее время молчит при успехе) |
agent.posttooluse | posttooluse-agent.sh | События открытого завершения хука после агента (например, отсутствующий шим, python_missing) |
manual.skill | Claude, выполняющий обычный режим | Ручной аудит, вызванный встроенно |
source.model записывает модель Claude Code, активную в сессии (например, "claude-sonnet-4-6"). Присутствует в схеме 2.1+; записи, созданные более старыми установками, опускают это поле. Команда статистики корректно переходит к "unknown", когда оно отсутствует.
Фильтруйте по source.component с помощью jq:```bash
jq -r '.source.component' audit.log | sort | uniq -c | sort -rn
jq -c 'select(.source.component == "bash.pretooluse")' audit.log
jq -c 'select(.source.mode == "fail_open") | {component: .source.component, reason: .fail_open.reason, ts}' audit.log
Для более простого анализа попросите Claude предоставить статистику использования вместо ручного разбора логов:```
"Show safer-dependencies stats for the last month"
Это предоставляет удобочитаемые сводки активности, влияния на безопасность и показателей производительности, извлечённые из этих журналов аудита.
Формы записей (схема 2.2). Три различные формы используют один и тот же заголовок ts / schema / source:
| Форма | Когда записывается | Отличительные поля |
|---|---|---|
| Запись аудита | Аудит манифеста / lockfile / bash-install | file, ecosystem, checked, findings, abandoned, stale, typosquat, unknown, signatures, notes, clean |
| Запись об ошибке установки | Ошибка установки при предварительной проверке шима (компонент shim.install_error) | install_error, shim_dir, scripts_dir |
| Запись fail-open | Любая точка входа хука завершается досрочно из-за helper_missing / shim_missing / python_missing. source.mode имеет значение "fail_open" | fail_open: { reason, detail? } |
Записи аудита: режим перехвата (Intercept Mode) выполняет полный конвейер (происхождение, возраст версии, OSV, abandoned/stale, typosquat, подписи), поэтому все массивы могут заполняться. Режим предварительной установки (Pre-Install Mode) сегодня выполняет только OSV, поэтому abandoned / stale / typosquat / signatures всегда пусты. Отправка после установки (аудит lockfile) записывается под shim.posttooluse с findings, заполняемыми строками WARNING: от аудиторов lockfile. Массив notes содержит информационные сигналы NOTE: (например, манифест пропущен, так как не закреплён).
Схема 2.2 добавила — аддитивно — четыре поля к lockfile-записям аудита: lockfile, manifest_ref, relation_summary (классификация direct/transitive/unknown каждого отмеченного пакета относительно парного манифеста) и блок policy, фиксирующий действующий уровень transitive. Это обновление обратно совместимо: читатели записей 2.1 допускают новые поля, а поле source.model остаётся присутствующим начиная с 2.1.```json
{
"ts": "2026-04-19T12:34:56Z",
"schema": "2.2",
"source": {
"component": "shim.posttooluse",
"script": "shim.sh",
"hook": "PostToolUse:Write",
"tool": "Write",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "/path/to/project/package.json",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": ["UPDATED: express 4.18.2 → 4.22.1 (HIGH: 1 CVE fixed)"],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Pre-Install Mode example (Bash hook, vulnerable pin denied):```json
{
"ts": "2026-04-23T06:56:21Z",
"schema": "2.2",
"source": {
"component": "bash.pretooluse",
"script": "pretooluse-bash.sh",
"hook": "PreToolUse:Bash",
"tool": "Bash",
"mode": "intercept",
"model": "claude-sonnet-4-6"
},
"file": "bash:npm install [email protected] [email protected]",
"ecosystem": "npm",
"checked": ["[email protected]", "[email protected]"],
"findings": [
"BLOCKED: [email protected] GHSA-35jh-r3h4-6jhm (CVSS:3.1/...): Command Injection in lodash"
],
"abandoned": [],
"stale": [],
"typosquat": [],
"unknown": [],
"signatures": [],
"notes": [],
"clean": ["[email protected]"]
}
Fail-open Mode example (Post-Install Bash hook called with no shim adjacent — broken install):```json { "ts": "2026-05-03T07:14:11Z", "schema": "2.2", "source": { "component": "bash.posttooluse", "script": "safer-dependencies-posttooluse-bash.sh", "hook": "PostToolUse", "tool": "Bash", "mode": "fail_open", "model": "claude-sonnet-4-6" }, "fail_open": { "reason": "shim_missing", "detail": "/home/alice/.claude/skills/safer-dependencies" } }
Запись с режимом fail-open означает: «этот хук сработал, но завершился досрочно без аудита, потому что отсутствовало какое-то обязательное условие». Используйте фильтр jq выше (`select(.source.mode == "fail_open")`), чтобы выявить каждое тихое событие потери защиты в вашем журнале.
Когда шим запускается в режиме пробного прогона (`SAFE_DEP_DRY_RUN=1`), записи также содержат `"mode": "dry_run"`, чтобы последующий анализ мог отфильтровать вызовы только для аудита.
## Требования
- Python 3.9+ (хуки проверяют его наличие и переходят в режим fail-open на более старых интерпретаторах)
- `curl` (для вызовов API реестра и проверок уязвимостей OSV)
- Инструменты экосистемы (необязательно, навык переключается на OSV API при их отсутствии):
- `npm` для пакетов npm
- `pip-audit` для пакетов Python
- `bundle` для пакетов Ruby
- `dependency-check` для пакетов Java
## FAQ
Обоснование проектных решений (почему `PostToolUse` вместо `PreToolUse`, почему подписи не проверяются, почему скрипты и шим дублируются, особенности загрузки навыков и т. д.) задокументировано в [`FAQ.md`](https://github.com/robert-auger/safer-dependencies/blob/main/FAQ.md).