ADG Оставить заявку
Блог DevOps 5 мин чтения

LLM в GitLab CI для code review безопасности: промпт, дефекты и ограничения

Подключили локальную LLM к GitLab CI для автоматической проверки безопасности merge request-ов: делимся структурой промпта и тем, что модель находит стабильно, а что - нет.

Контекст момента

GitLab Duo Code Review и GitHub Copilot Enterprise - LLM-помощники в цикле code review стали mainstream в 2024

GitLab в этом году запустил Duo Code Review, GitHub добавил Copilot Enterprise с code review-возможностями - LLM в цикле проверки кода перестала быть экзотикой. Для клиентов с изолированным контуром это всё по-прежнему недоступно: облачный сервис, данные уходят наружу, для КИИ неприемлемо. Решили не ждать, когда кто-то придумает on-premise вариант, и собрали своё - локальная модель в GitLab CI pipeline, которая смотрит на diff каждого merge request с точки зрения безопасности.

Зачем вообще это делать

У нас давно был SAST в пайплайне - GitLab SAST с Semgrep-правилами и отдельный trivy для зависимостей. Они хорошо ловят конкретные паттерны: захардкоженные секреты, известные уязвимые версии библиотек, конкретные опасные вызовы. Но есть класс проблем, который они системно пропускают: логические дыры в авторизации, некорректная обработка входных данных, race condition в многопоточном коде, небезопасное использование криптографии без формального нарушения правил. Это то, что обычно ловит человек при code review - если он думает о безопасности, а не только о том, работает ли логика.

Идея: добавить ещё один шаг в пайплайн, который смотрит на diff и высказывает мнение именно с позиции безопасности.

Как устроено технически

Инфраструктура та же, что описывали в августе в посте про LLM-агентов в ИТ-операциях: модель запущена локально через llama.cpp на GPU-сервере в контуре, доступна по HTTP. В этот раз взяли CodeLlama 34B-Instruct - она лучше работает с кодом, чем base-версия.

В пайплайн добавили отдельную стадию security-llm-review. GitLab CI job делает три вещи:

  1. Получает diff текущего MR через GitLab API (/api/v4/projects/:id/merge_requests/:iid/changes).
  2. Фильтрует diff: оставляет только добавленные строки (+), обрезает по размеру - если diff больше порога, берём только изменённые файлы, исключая локи и сгенерированный код.
  3. Отправляет в модель и возвращает результат как комментарий к MR через API.

Job не блокирующий - он не валит пайплайн, только оставляет комментарий. Решение о блокировке остаётся за человеком.

Структура промпта

Это оказалось самой важной частью работы. Первые эксперименты с простым «посмотри на код, найди уязвимости» давали мусор: модель писала длинные общие рассуждения, придумывала проблемы, которых не было, и пропускала реальные.

Текущая структура промпта (упрощённо):

Ты - security reviewer. Анализируй только предоставленный diff.
Твоя задача - найти реальные проблемы безопасности, не теоретические.

Категории проблем, на которые смотреть:
- Авторизация и аутентификация: пропущенные проверки, небезопасные сравнения
- Обработка входных данных: отсутствие валидации, потенциальный injection
- Управление секретами: захардкоженные данные, небезопасное логирование
- Криптография: слабые алгоритмы, небезопасная генерация случайных чисел
- Управление сессиями и состоянием: race condition, небезопасная десериализация

Для каждой найденной проблемы укажи:
- Строку в diff
- Тип проблемы (из списка выше)
- Конкретное объяснение риска
- Предлагаемое исправление

Если серьёзных проблем нет - скажи об этом прямо.
Не придумывай проблем. Лучше пропустить, чем выдать ложный срабатыванием.

Ключевой элемент - явная инструкция «лучше пропустить». Без неё модель выдаёт десять потенциальных проблем на каждый diff, три четверти из которых - шум. С ней количество срабатываний падает, но качество растёт: инженеры перестают игнорировать комментарии.

Что модель находит стабильно

После нескольких недель работы сложилась картина, где LLM реально помогает.

Пропущенные проверки авторизации. Новый endpoint или метод без декоратора авторизации - модель замечает это надёжно. Видимо, паттерн хорошо представлен в обучающих данных. Не всегда правильно интерпретирует контекст (иногда проверка выше по стеку), но сигнал выдаёт.

Логирование чувствительных данных. logger.info(f"User {user.email} logged in with password {password}") - такое модель ловит хорошо. Это паттерн с чёткой сигнатурой.

Небезопасная конкатенация в запросах. SQL или LDAP через f-string или + без параметризации - находит стабильно, хотя иногда путается с ORM-методами.

Слабые алгоритмы хеширования. MD5 и SHA1 для паролей - модель понимает, что это проблема, и объясняет почему.

Где промахивается

Логические уязвимости авторизации. Если проверка авторизации есть, но написана неправильно (например, проверяется role вместо permission, или условие инвертировано) - это модель часто не видит. Нужен контекст всей модели данных, которого в diff нет.

Race condition. Если проблема проявляется только в многопоточном контексте и не очевидна из diff - почти всегда пропускается.

Бизнес-логика. «Здесь цена вычисляется на клиенте и передаётся на сервер» - это проблема, но чтобы её заметить, надо понимать бизнес-контекст. Модель не понимает.

Сложные криптографические схемы. Если кто-то сделал что-то неочевидно неправильное с nonce или IV - модель скорее всего не заметит.

Где сейчас

Pipeline работает на нескольких проектах уже месяц. Инженеры в целом приняли нормально: ещё один комментарий в MR, иногда полезный. Ложных срабатываний стало меньше после итерации по промпту. Реальных проблем, которые модель нашла и человек подтвердил - несколько штук, из них одна была нетривиальной: пропущенная проверка прав на bulk-операцию, которая тихо проехала бы через SAST.

Это не замена security review и не замена SAST. Это дополнительный слой, который закрывает часть пробела между автоматическими анализаторами и внимательным человеком. Пока инструмент ведёт себя достаточно честно: говорит о проблемах, которые умеет видеть, и не претендует на большее.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.