Руководство
Практический чек-лист ревью кода, сгенерированного ИИ, перед мержем
Десять вещей, которые стоит проверить в коде от ассистента: от выдуманных зависимостей и проверок доступа только в браузере до проглоченных ошибок и пустых тестов.
· 9 мин чтения · Команда vetkit


Код от ассистента обычно компилируется, хорошо читается и делает примерно то, что вы просили. Именно поэтому его так легко пропустить без вопросов. Ошибки редко бывают синтаксическими. Это решения, которые модель приняла молча: зависимость, которая, по её мнению, существует, проверка прав не в том месте, ошибка, которую она решила проигнорировать.
Это чек-лист, которым мы пользуемся при ревью изменений, сделанных с помощью ИИ. Он не о том, насколько элегантен код. Он о небольшом наборе проблем, которые превращаются в инциденты.
Почему коду от ИИ нужно другое ревью
Когда код пишет коллега, обычно можно доверять тем частям, о которых он не упомянул. Он знал кодовую базу, проверил изменение локально и сказал бы, если что-то недоделано. У модели нет этого контекста, если вы его не дали, и она склонна заполнять пробелы чем-то правдоподобным, а не вопросом. Поэтому ревью смещается с «хорошо ли это написано» на «что она предположила».
1. Зависимости
Проверьте каждый пакет, который добавляет изменение. Существует ли он в реестре? Это тот пакет, который рекомендует официальная документация, или похожий по названию? Не опубликован ли он на прошлой неделе? Модели иногда выдумывают имена пакетов, и некоторые из этих имён регистрируют злоумышленники. В нашем руководстве по slopsquatting рассказано, как проверить пакет за минуту.
Посмотрите и на версии. Версия, закреплённая на том, что никогда не выпускалось, сломает следующую чистую установку, а незакреплённая зависимость означает, что код, который вы проверили, — не тот код, который будет работать.
2. Секреты и публичные переменные
Поищите в диффе ключи, токены и пароли, в том числе в тестовых файлах и примерах. Затем посмотрите на переменные окружения с публичными префиксами, такими как VITE_, NEXT_PUBLIC_ или EXPO_PUBLIC_. Всё с этими префиксами копируется в браузерный бандл во время сборки. Ассистент может переименовать секрет под один из них, чтобы функция заработала в браузере. Это руководство разбирает вариант этой ошибки с API-ключом LLM.
3. Где проверяется доступ
Найдите строку, которая решает, может ли текущий пользователь сделать это действие. Если она в React-компоненте, route guard или скрытой кнопке, это функция пользовательского интерфейса, а не безопасность. Кто угодно может вызвать ваш API напрямую. Проверка должна выполняться на сервере, для каждого запроса, применительно к запрашиваемому ресурсу: не только «вошёл ли пользователь», но и «принадлежит ли этому пользователю этот счёт».
Обращайте внимание на новые API-маршруты вообще без auth middleware и на бэкенды вроде Supabase или Firebase, где база данных доступна из браузера. Там защитой служат собственные правила базы данных. Таблица Supabase без row level security открыта любому, у кого есть ваш публичный anon key.
4. Недоверенный ввод
Проследите пользовательский ввод от точки входа до места использования. SQL, собранный конкатенацией строк, shell-команды из полей запроса, пути к файлам из query-параметров, HTML, отрисованный из пользовательского контента, и URL, запрашиваемые от имени пользователя, — классические паттерны инъекций, path traversal, XSS и SSRF. Ассистенты всё ещё их производят, в основном когда окружающий код уже делает что-то похожее.
// Looks harmless, is an injectiondb.query(`SELECT * FROM users WHERE email = '${req.query.email}'`); // Parameterizeddb.query('SELECT * FROM users WHERE email = $1', [req.query.email]);5. Недописанный код
Длинные генерации иногда обрываются. Поищите в изменении заглушки: TODO, «implement later», «rest of the code here», функции, возвращающие захардкоженные тестовые данные, фиктивные учётные данные и файлы с именами вроде utils copy.ts. Ищите и тотальные подавления, такие как // @ts-ignore, eslint-disable в начале файла или any, используемый, чтобы заглушить проверку типов. Часто за ними прячется ровно та проблема, которую модель не смогла решить.
6. Обработка ошибок
Блок catch, который логирует и продолжает работу или ловит всё подряд и возвращает пустой результат, превращает громкий сбой в тихую потерю данных. Спросите себя, что должно происходить, если этот вызов упадёт, и делает ли код именно это. С подозрением относитесь к повторным попыткам без ограничений и к ошибкам, которые превращаются в успешные ответы.
7. Тесты
Сгенерированные тесты стоит читать построчно. Типичные проблемы: тесты, которые ничего не проверяют (нет ни одного assert), тесты, которые мокают ту самую функцию, которую тестируют, проверки, что функция просто была вызвана, и забытые .only или .skip. Проходящий набор тестов ничего не доказывает, пока вы не знаете, что он может упасть. Один раз намеренно сломайте код и посмотрите, заметит ли это какой-нибудь тест.
8. Таймауты и блокирующие вызовы
Исходящие HTTP-вызовы без таймаута — это инцидент в продакшене, который ждёт лишь медленной зависимости. Многие популярные клиенты по умолчанию ждут бесконечно, включая requests в Python и http.DefaultClient в Go. В Node.js синхронные файловые операции или хеширование паролей внутри обработчика запроса блокируют все остальные запросы в этом процессе. Локально это редко проявляется, потому что ваш ноутбук и ваши зависимости быстрые и ничем не загружены.
9. Доступ к данным
Ищите запросы внутри циклов (проблема N+1), эндпоинты списков, возвращающие все строки без пагинации, и клиенты базы данных, создаваемые на каждый запрос вместо общего. Внимательно проверяйте и миграции: синхронизация схемы при запуске или миграция, которая удаляет и пересоздаёт таблицу, может стереть продакшн-данные при следующем деплое.
10. Функции на базе LLM
Если изменение вызывает модель, считайте её вывод недоверенным вводом. Его нельзя выполнять, подставлять в SQL или отрисовывать как сырой HTML. Проверьте, что API-ключ остаётся на сервере, что маршрут, вызывающий модель, требует авторизованного пользователя и имеет rate limit, а длина вывода ограничена. Если у агента есть инструменты, проверьте, что эти инструменты умеют и может ли текст из документов или веб-страниц ими управлять.
Сделайте это рутиной
Десять проверок на каждый pull request — это много для ручной работы, а смысл чек-листа в том, чтобы перестать полагаться на память. Большинство пунктов можно автоматизировать, хотя бы частично. Тогда ваше внимание остаётся для того, в чём инструменты плохи, например для вопроса, делает ли изменение то, что действительно нужно продукту.
vetkit группирует эти проверки в наборы: безопасность (секреты, уязвимые зависимости, уязвимости в коде, конфигурация инфраструктуры), качество кода, устойчивость, риски ИИ-кода (выдуманные пакеты, недописанный код, подводные камни платформ для приложений, безопасность LLM и агентов) и готовность к продакшену (таймауты, блокирующие вызовы, работа с базой данных, операционные основы). Он читает ваш код, не устанавливая, не собирая и не запуская его, и сообщает о находках с указанием файла, строки и предлагаемого исправления. Как и любой статический анализ, он может что-то пропустить и может ошибаться, поэтому он дополняет ревью, а не заменяет его.