Статический анализ в Git: что он ловит, а что пропускает
Линтеры, типизаторы, SAST и сканеры секретов решают разные задачи. Разбираем, что запускать до коммита и в CI, какие ошибки видны без выполнения кода, а где статический анализ бессилен.

Статический анализ может остановить коммит с утёкшим токеном, найти SQL-инъекцию в очевидном месте и показать несовместимый тип ещё до запуска тестов. Но он не узнает, что платёжный сервис недоступен, а бизнес-правило неверно, если это не выражено в коде или проверках. Поэтому Git-пайплайн из одного линтера почти всегда создаёт ложное чувство безопасности.
Какие задачи решают инструменты
Под «статическим анализом» обычно смешивают несколько классов проверок. Они читают файлы и историю изменений, но не выполняют приложение в обычном сценарии. Разница между ними важна: форматтер не ищет секреты, а сканер зависимостей не проверяет типы.
| Класс | Что находит | Чего не знает | Где запускать |
|---|---|---|---|
| Форматтер и линтер | Стиль, неиспользуемые импорты, часть очевидных ошибок | Реальное поведение сервиса и корректность требований | До коммита и в CI |
| Проверка типов | Несовпадение типов, часть ошибок в контрактах функций | Данные, которые придут из сети, БД или пользователя | В CI, иногда локально |
| SAST | Опасные конструкции: часть инъекций, небезопасные вызовы, ошибки потоков данных | Проблемы, зависящие от конфигурации и окружения | В CI и на изменённых файлах |
| Сканер секретов | Ключи, токены и пароли по шаблонам и эвристикам | Новый формат секрета, если его нельзя распознать | До отправки в удалённый репозиторий |
| Сканер зависимостей | Известные уязвимости в библиотеках и образах | Уязвимость без записи в базе и небезопасное использование API | В CI и по расписанию |
Статический анализ отвечает на вопрос «что подозрительного видно в артефактах». Он не отвечает на вопрос «правильно ли продукт решает задачу пользователя».
Поток данных1 — путь значения от источника, например HTTP-параметра, до опасной операции: SQL-запроса, запуска команды или вывода в HTML. SAST пытается проследить такой путь без запуска приложения.
Что проверять до коммита
Локальный Git-хук нужен для быстрых и почти бесспорных проверок. Он не должен запускать полный набор SAST на каждом сохранении: разработчик будет ждать несколько минут и начнёт обходить проверку.
1. Ошибки в самом diff
Начните с встроенной проверки Git:
git diff --check
Она показывает пробелы в конце строк и некоторые ошибки в конфликтных маркерах. Это дешёвая проверка: её можно запускать перед каждым коммитом и не обсуждать с командой порог чувствительности.
2. Линтер и форматирование
Для Python-проекта с Ruff 0.6+ типичный быстрый запуск выглядит так:
ruff check .
ruff format --check .
Линтер ловит локальные нарушения: неиспользуемые импорты, часть подозрительных конструкций и правила проекта. Форматтер снижает шум в diff, но не доказывает корректность алгоритма. В другом языке подставьте его штатный инструмент, а не пытайтесь заменить все проверки универсальным скриптом.
3. Секреты
Gitleaks 8.x можно запускать до отправки изменений в репозиторий:
gitleaks detect --source .
Сканер ищет совпадения с известными форматами ключей и подозрительные строки. Если он нашёл настоящий секрет, удаление строки из последнего файла не всегда достаточно: значение могло остаться в истории Git. Такой ключ нужно отозвать или заменить у владельца сервиса, а очистку истории проводить отдельной процедурой.
Что переносить в CI
Проверки, которым нужны полная история, база уязвимостей или много времени, лучше выполнять на сервере. Локальный хук можно отключить, изменить или не установить, а результат CI становится частью правила слияния.
Типы и зависимости
Проверка типов полезна там, где команда действительно поддерживает типовые аннотации. Например, mypy 1.11+ может показать, что функция объявлена как возвращающая строку, но в одной ветке отдаёт значение другого типа:
mypy .
Это проверка контракта программы, а не проверка значений. Строка, пришедшая из JSON, всё равно требует валидации на границе приложения.
Для зависимостей и файловой системы часто используют Trivy 0.5x:
trivy fs .
Результат зависит от базы уязвимостей и версии сканера. Фиксируйте версию инструмента и сохраняйте отчёт в CI, иначе через месяц тот же коммит может показать другой результат из-за обновления базы.
SAST не равен тестированию безопасности
Semgrep 1.x способен искать опасные шаблоны и отслеживать некоторые потоки данных. В простом случае запуск выглядит так:
semgrep scan --config auto
Правило может увидеть использование пользовательского ввода в опасной функции, но не поймёт без дополнительного контекста, что конкретный middleware уже экранирует значение. Поэтому каждое срабатывание требует классификации: исправить, настроить источник или приёмник, либо обоснованно подавить с пояснением.
Что инструменты ловят плохо
Бизнес-ошибки
Если скидка должна применяться только к первой покупке, статический анализ не узнает это из функции, которая складывает два числа. Он также не проверит, что часовой пояс выбран правильно, письмо отправлено нужному клиенту, а отменённый заказ не попал в отчёт о выручке. Здесь нужны тесты, ревью требований и проверки на уровне сценариев.
Проблемы окружения
Код может пройти все проверки и вернуть 502 в проде из-за неверного DNS, лимита соединений или отсутствующей переменной окружения. Статические инструменты видят имя переменной, но обычно не могут подтвердить, что она задана с правильным значением в конкретном кластере.
Динамические конструкции
Отражение, генерация SQL, шаблонов или команд затрудняют анализ. Инструмент может дать предупреждение там, где риск уже закрыт, или пропустить опасность, если путь значения проходит через динамический код, отдельный сервис и конфигурацию.
Как собрать проверки без тормозов
- На локальном этапе оставьте
git diff --check, форматирование, быстрый линтер и сканер секретов. Цель — получить ответ за секунды, а не полный аудит проекта. - В pull request запускайте типизацию, тесты, SAST и проверку зависимостей. Проверяйте весь проект, если инструмент анализирует связи между файлами; режим только для изменённых строк используйте лишь там, где это поддерживается корректно.
- По расписанию повторяйте сканирование зависимостей и секретов по всей истории или рабочему дереву. Новая запись в базе уязвимостей может появиться после слияния кода.
- Для каждого блокирующего правила назначьте владельца и срок исправления. Иначе команда начнёт добавлять исключения, а отчёт потеряет смысл.
- Собирайте метрики: время проверки, долю ложных срабатываний, возраст открытых предупреждений и число дефектов, найденных после слияния. Без этих данных нельзя понять, помогает ли инструмент.
Когда какой подход выбирать
Небольшому проекту не нужен десяток анализаторов с пересекающимися правилами. Начните с цепочки, соответствующей риску:
- для веб-приложения — линтер, проверка типов, тесты, SAST и сканирование секретов;
- для библиотеки — линтер, типы, тесты совместимости и сканирование зависимостей;
- для инфраструктурного репозитория — форматирование конфигураций, проверка секретов, анализ образов и планирование изменений;
- для проекта с чувствительными данными — обязательное сканирование секретов до публикации и отдельная процедура отзыва уже раскрытых ключей.
Главный критерий — не количество предупреждений, а стоимость пропуска ошибки. Если утёкший токен можно отозвать за минуту, блокируйте публикацию сразу. Если правило SAST даёт сотни ложных срабатываний на каждый PR, сначала настройте область анализа и исключения, а не добавляйте ещё один сканер.
Что ломается первым
- Хук не запускается. Разработчик не установил его или выполняет коммиты из среды, где Git использует другой каталог хуков. Критичные проверки должны дублироваться в CI.
- Секрет найден в тестовом файле. Не добавляйте бездумное исключение по всей директории. Разделите безопасные фикстуры и реальные значения, а исключение ограничьте конкретной строкой.
- Пайплайн завален предупреждениями. Введите режим baseline для уже существующих находок, но новые предупреждения оставьте блокирующими. Конкретный механизм зависит от инструмента и его версии.
- Сканер не видит проблему в сгенерированном коде. Проверьте, входит ли каталог в область анализа, и не выдаёт ли генератор артефакты после запуска проверки. Сгенерированный код обычно лучше проверять на этапе сборки и не редактировать вручную.
Что делать дальше
Зафиксируйте версии Git 2.45+, Ruff 0.6+, mypy 1.11+, Semgrep 1.x, Gitleaks 8.x и Trivy 0.5x в документации проекта, а точные версии инструментов — в используемом менеджере зависимостей или CI-образе. Затем возьмите один pull request и измерьте полный цикл: сколько занимают проверки, какие находки повторяются и сколько из них подтверждаются ревьюером. Следующим шагом настройте блокировку только для новых критичных проблем, а бизнес-правила вынесите в тесты.
1 Поток данных, или data flow, — последовательность передачи значения между источником и операцией, которая может создать риск.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: Git hooks — официальная документация Git, Semgrep Documentation
Частые вопросы
Можно ли ограничиться линтером и форматтером?
Остановит ли сканер секретов уже опубликованный ключ?
Почему SAST показывает ошибку там, где всё безопасно?
Нужно ли запускать все проверки до каждого коммита?
Может ли статический анализ доказать, что приложение безопасно?
Что делать, если новая версия инструмента даёт другие результаты?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.