Инструменты InterLAB · 42 правила с доказательствами · без изменения кода

Ревьюер кода, в том числе написанного ИИ

Независимое ревью pull request только на чтение: 42 опубликованных правил по безопасности, миграциям, тестам, архитектуре и надёжности. Каждое замечание — с файлом и строкой, фрагментом кода, объяснением и способом проверки. Код не изменяется и не выполняется.

Бесплатно, без регистрации

git diff, git format-patch или .diff/.patch из PR на GitHub/GitLab. Код не выполняется, не изменяется и никуда не отправляется.

Контекст проекта

Пакеты правил включаются автоматически по признакам в diff. Можно включить или выключить их явно.

Признаков не найдено — пакет не применяется. Признаки: .sql, миграции, pg/psycopg/prisma

Признаков не найдено — пакет не применяется. Признаки: каталог supabase/, @supabase/*, SUPABASE_*

Признаков не найдено — пакет не применяется. Признаки: *.rules, firebase.json, firebase

Признаков не найдено — пакет не применяется. Признаки: app/**/page|route, next.config, "use client", next/*

Языки

Ничего не выбрано — проверяются все языки по расширениям файлов. Если выбрать языки, правила для остальных будут пропущены.

Как работает ревьюер

  1. Diff

    Вставьте unified diff (git diff, git format-patch, .diff/.patch из PR на GitHub или GitLab) или загрузите файл.

  2. Контекст проекта

    Пакеты правил для PostgreSQL, Supabase, Firebase и Next.js App Router включаются автоматически по признакам в diff (PostgreSQL — .sql, миграции, pg/psycopg/prisma; Supabase — каталог supabase/, @supabase/*, SUPABASE_*; Firebase — *.rules, firebase.json, firebase; Next.js App Router — app/**/page|route, next.config, "use client", next/*); их можно включить или выключить вручную. Можно ограничить проверку языками.

  3. Правила

    Каждое правило смотрит на добавленные строки (исключения указаны) и сообщает файл, строку новой версии, фрагмент с контекстом, почему это важно и как проверить. Автоисправлений нет — решение за человеком.

  4. Решение ревьюера

    У замечания — статус «исправить», «принятый риск» или «ложное срабатывание», заметка и имя. Решения сохраняются при повторной проверке: ключ замечания строится из правила, файла и текста строки, а не номера строки.

  5. Экспорт

    Markdown для комментария в PR, PDF через печать, JSON для возврата к ревью и SARIF 2.1.0 для GitHub code scanning.

Правила

Таблицы ниже строятся из того же кода, что и проверка, — правила v1.0 (13.10.2026). Важность: критично, высокая, средняя, низкая, информация.

CR-SEC-001

Что ищем
Похоже на секрет в добавленной строке
Как обнаруживается
Шаблоны ключей (AWS, GitHub, GitLab, Slack, Stripe, Google, Anthropic, OpenAI, JWT, Telegram, приватные ключи, строки подключения с паролем) и присваивания вида password=… (плейсхолдеры вроде process.env, ${VAR}, changeme не считаются).
Важность
критично
Как проверить
Проверьте, настоящее ли это значение. Если да — отзовите и перевыпустите ключ, перенесите его в переменные окружения или хранилище секретов, очистите историю.

CR-SEC-002

Что ищем
Файл .env добавлен или изменён в репозитории
Как обнаруживается
Файл .env, .env.local, .env.production и т. п. (кроме .env.example/.sample/.template) добавлен или изменён.
Важность
высокая
Как проверить
Убедитесь, что файл есть в .gitignore, а в репозитории лежит только .env.example без значений. Если значения настоящие — смените их.

CR-SEC-003

Что ищем
Выполнение кода из строки (eval и аналоги)
Как обнаруживается
JS/TS: eval(), new Function(), setTimeout/setInterval со строкой; Python: eval()/exec(); PHP, Ruby: eval().
Важность
высокая
Как проверить
Найдите, откуда берётся строка. Обычно eval заменяется разбором JSON, таблицей функций или безопасным парсером выражений.

CR-SEC-004

Что ищем
Команда оболочки собирается из переменных
Как обнаруживается
child_process exec/execSync с шаблонной строкой или конкатенацией, spawn/execFile с shell: true; subprocess с shell=True, os.system/os.popen со вставкой; exec.Command("sh", "-c", …); shell_exec/system с переменной PHP; обратные кавычки с #{} в Ruby.
Важность
высокая
Как проверить
Передавайте аргументы массивом (execFile/spawn без shell, subprocess.run([...])) и проверьте, может ли значение прийти от пользователя.

CR-SEC-005

Что ищем
SQL-запрос собирается вставкой значений в строку
Как обнаруживается
Строка с SELECT … FROM / INSERT INTO / UPDATE … SET / DELETE FROM и в той же строке — вставка: ${} в шаблонной строке, конкатенация +, f-строка, %, .format(), fmt.Sprintf, $переменная в PHP, #{} в Ruby. Безопасные тегированные шаблоны (sql…, Prisma.sql…, $queryRaw…) не считаются.
Важность
высокая
Как проверить
Используйте параметры ($1, ?, :name) или построитель запросов. Если значение — имя столбца из белого списка, это допустимо: проверьте список.

CR-SEC-006

Что ищем
HTML вставляется без экранирования
Как обнаруживается
dangerouslySetInnerHTML, innerHTML/outerHTML =, insertAdjacentHTML, document.write, v-html, фильтр |safe, autoescape off, mark_safe, Markup(), {!! !!} в Blade, .html_safe, <%==, {{{ }}}. Очистка innerHTML = "" не считается.
Важность
средняя
Как проверить
Проверьте источник HTML. Данные пользователя — только через санитайзер (например, DOMPurify) или как текст.

CR-SEC-007

Что ищем
Отключена проверка TLS-сертификата
Как обнаруживается
rejectUnauthorized: false, NODE_TLS_REJECT_UNAUTHORIZED=0, verify=False, InsecureSkipVerify: true, CURLOPT_SSL_VERIFYPEER false, ssl._create_unverified_context, strictSSL: false, check_hostname=False, VERIFY_NONE, ServerCertificateValidationCallback => true.
Важность
высокая
Как проверить
Если это локальная отладка — ограничьте настройку окружением разработки. Для своего CA укажите сертификат явно (ca, verify=путь).

CR-SEC-008

Что ищем
CORS: любой источник вместе с учётными данными
Как обнаруживается
В добавленных строках одного файла есть и разрешение любого источника (Access-Control-Allow-Origin: *, origin: '*' или true, allow_origins=["*"], AllowAllOrigins, AllowAnyOrigin), и разрешение cookies (credentials: true, Allow-Credentials: true, allow_credentials=True).
Важность
высокая
Как проверить
Задайте явный список доверенных источников. Убедитесь, что origin: true не отражает любой входящий Origin.

CR-SEC-009

Что ищем
JWT читается без проверки подписи
Как обнаруживается
jwt.decode() без jwt.verify() в добавленных строках того же файла (jsonwebtoken), algorithm(s) "none", ignoreExpiration: true, PyJWT decode с verify_signature=False / verify=False, ParseUnverified в Go.
Важность
высокая
Как проверить
Используйте verify с явным списком алгоритмов и секретом/ключом; decode — только для чтения уже проверенного токена.

CR-SEC-010

Что ищем
MD5 или SHA-1 для паролей
Как обнаруживается
Вызов md5/sha1 (createHash, hashlib, MessageDigest, Digest::MD5, md5()) в строке, где рядом (±3 добавленные строки) упоминается пароль или секрет.
Важность
высокая
Как проверить
Для паролей используйте bcrypt, scrypt или Argon2 с солью. MD5 для контрольной суммы файла допустим — тогда отметьте как ложное срабатывание.

CR-SEC-011

Что ищем
Небезопасный генератор случайных чисел для токена или кода
Как обнаруживается
Math.random(), random.* в Python, rand()/mt_rand()/uniqid() в PHP, new Random() в Java, math/rand в Go — в строке со словами token, secret, password, otp, nonce, salt, session, key, code, invite, reset, uuid.
Важность
средняя
Как проверить
Используйте crypto.randomUUID()/crypto.getRandomValues(), secrets в Python, random_bytes() в PHP, SecureRandom в Java, crypto/rand в Go.

CR-SEC-012

Что ищем
Перенаправление на адрес из запроса
Как обнаруживается
redirect(...) с req.query/params/body, request.args/GET, searchParams.get(), $_GET; location = params.get(...); redirect_to params[...].
Важность
средняя
Как проверить
Разрешайте только относительные пути или адреса из белого списка; проверяйте, что адрес начинается с одного «/», а не «//».

CR-SEC-013

Что ищем
Ключ service_role Supabase в клиентском коде (пакет: Supabase)
Как обнаруживается
service_role / SERVICE_ROLE в файле с "use client" (или *.client.tsx), либо переменная NEXT_PUBLIC_/VITE_/REACT_APP_/EXPO_PUBLIC_…SERVICE_ROLE в любом файле.
Важность
критично
Как проверить
Ключ service_role — только на сервере (route handler, server action, edge function) без префикса NEXT_PUBLIC_. В клиенте — anon-ключ и политики RLS. Если ключ уже попал в сборку — перевыпустите его.

CR-SEC-014

Что ищем
RLS отключён или политика пропускает всех (пакет: Supabase / PostgreSQL)
Как обнаруживается
ALTER TABLE … DISABLE ROW LEVEL SECURITY, USING (true), WITH CHECK (true), GRANT ALL … TO anon/public в .sql и миграциях.
Важность
высокая
Как проверить
Проверьте, что таблица действительно публичная (например, справочник). Иначе — политика с условием по auth.uid() и роли.

CR-SEC-015

Что ищем
Правила Firebase открывают данные всем (пакет: Firebase)
Как обнаруживается
allow … : if true; allow read, write; без условия; тестовый режим if request.time < timestamp.date(…); ".read"/".write": true в Realtime Database.
Важность
критично
Как проверить
Разрешайте доступ по request.auth и владельцу документа; проверьте правила в эмуляторе Firebase.

CR-SEC-016

Что ищем
Режим отладки в боевой конфигурации
Как обнаруживается
DEBUG = True в settings/config, app.run(debug=True), а также FLASK_DEBUG/APP_DEBUG/DEBUG=true или debug: true в файлах с prod/production в пути.
Важность
средняя
Как проверить
Включайте отладку только переменной окружения разработки и проверьте значение на боевом сервере.

CR-SEC-017

Что ищем
В лог пишется пароль, токен или ключ
Как обнаруживается
Вызов логирования (console.*, logger.*, logging.*, print, fmt.Print*, System.out, puts, error_log) с переменной, в имени которой password, secret, token, api_key, authorization, cookie, card, cvv, ssn. Слова внутри строковых литералов не считаются.
Важность
средняя
Как проверить
Уберите значение из лога или маскируйте его; проверьте, не осталось ли уже записанных значений.

CR-SEC-018

Что ищем
Небезопасная десериализация
Как обнаруживается
pickle.load(s), yaml.load без SafeLoader, yaml.unsafe_load, Marshal.load, unserialize($_GET/$_POST/…), new ObjectInputStream.
Важность
высокая
Как проверить
Убедитесь, что данные приходят только из доверенного источника; для внешних данных — JSON или yaml.safe_load.

CR-SEC-019

Что ищем
Права 777 на файлы или каталоги
Как обнаруживается
chmod 777, chmod(…, 0o777), os.chmod(…, 0o777), os.Chmod/MkdirAll/WriteFile с 0777.
Важность
средняя
Как проверить
Выдайте минимально нужные права (обычно 644 для файлов, 755 для каталогов) и владельца.
Безопасность

CR-MIG-001

Что ищем
Удаление таблицы или столбца
Как обнаруживается
DROP TABLE, DROP COLUMN, TRUNCATE TABLE, dropTable/dropColumn, op.drop_table/drop_column, remove_column, drop_table, dropIfExists.
Важность
высокая
Как проверить
Проверьте бэкап и план отката; удаляйте в два релиза: сначала перестаньте использовать столбец, затем удалите. Если это down-миграция — отметьте как ложное срабатывание.

CR-MIG-002

Что ищем
Новый столбец NOT NULL без значения по умолчанию
Как обнаруживается
ADD [COLUMN] … NOT NULL без DEFAULT в той же строке; add_column … null: false без default:; op.add_column(… nullable=False) без server_default.
Важность
высокая
Как проверить
Добавьте столбец nullable или с DEFAULT, заполните данные, затем включите NOT NULL отдельным шагом.

CR-MIG-003

Что ищем
Переименование столбца или таблицы
Как обнаруживается
RENAME COLUMN, ALTER TABLE … RENAME TO, RENAME TABLE, renameColumn, rename_column/rename_table, op.alter_column(new_column_name=…), sp_rename.
Важность
средняя
Как проверить
Найдите все обращения к старому имени; при выкате без простоя — новый столбец, двойная запись, переключение, удаление старого.

CR-MIG-004

Что ищем
Изменение типа столбца
Как обнаруживается
ALTER COLUMN … [SET DATA] TYPE, MODIFY COLUMN, change_column, op.alter_column(type_=…).
Важность
средняя
Как проверить
Оцените размер таблицы и время блокировки на копии данных; проверьте, что все значения помещаются в новый тип.

CR-MIG-005

Что ищем
CREATE INDEX без CONCURRENTLY (PostgreSQL) (пакет: PostgreSQL)
Как обнаруживается
CREATE [UNIQUE] INDEX без CONCURRENTLY на таблице, которая не создаётся в этом же файле.
Важность
средняя
Как проверить
Для больших таблиц используйте CREATE INDEX CONCURRENTLY (вне транзакции миграции). Для маленьких или новых таблиц — отметьте как принятый риск.

CR-MIG-006

Что ищем
Изменена уже существующая миграция
Как обнаруживается
Файл в каталоге миграций (migrations/, db/migrate/, alembic/versions/, prisma/migrations/, supabase/migrations/) изменён, а не добавлен.
Важность
высокая
Как проверить
Если миграция уже применялась где-либо, верните её и оформите изменение новой миграцией.

CR-MIG-007

Что ищем
DELETE или UPDATE без WHERE
Как обнаруживается
В .sql — оператор DELETE FROM / UPDATE … SET без WHERE (по добавленным строкам до «;»); в коде — строка с таким запросом целиком в одной строке без WHERE.
Важность
высокая
Как проверить
Убедитесь, что изменение всех строк задумано (например, заполнение нового столбца), и проверьте его на копии данных.
Миграции

CR-TST-001

Что ищем
Код изменён, тесты — нет
Как обнаруживается
В diff есть изменённые файлы кода (не миграции и не сгенерированные), но ни одного тестового файла (по соглашениям путей).
Важность
средняя
Как проверить
Проверьте, покрыто ли поведение существующими тестами; если нет — добавьте тест на изменённую ветку логики.

CR-TST-002

Что ищем
Фокус на одном тесте (.only)
Как обнаруживается
describe/it/test/context.only(…), fit(, fdescribe( в тестовых файлах.
Важность
высокая
Как проверить
Уберите .only; включите в CI запрет (например, --forbid-only в Mocha/Playwright, правило no-focused-tests).

CR-TST-003

Что ищем
Тест отключён (skip)
Как обнаруживается
.skip/.todo, xit/xdescribe/xtest, @pytest.mark.skip/skipif/xfail, @unittest.skip, t.Skip, @Disabled, @Ignore, skip/pending в RSpec.
Важность
средняя
Как проверить
Должна быть причина и задача на возврат теста. Если тест мешал зелёному CI — разберитесь с причиной падения.

CR-TST-004

Что ищем
Из тестов удалены проверки
Как обнаруживается
В тестовом файле удалено больше строк с проверками (expect, assert*, should, t.Error/Fatal, require.*, assertThat), чем добавлено. Проверяются удалённые строки.
Важность
средняя
Как проверить
Сравните удалённые и новые проверки: покрывают ли новые то же поведение?

CR-TST-005

Что ищем
Крупное обновление снимков (snapshots)
Как обнаруживается
Файл снимков изменён на 200+ строк.
Важность
низкая
Как проверить
Просмотрите отличия снимков выборочно; убедитесь, что обновление ожидаемо из-за изменений в этом PR.
Тесты

CR-ARC-001

Что ищем
Новые зависимости
Как обнаруживается
Новые пакеты в package.json, requirements*.txt, pyproject.toml, Pipfile, go.mod, Cargo.toml, Gemfile, composer.json (пакет есть в добавленных строках и отсутствует в удалённых).
Важность
информация
Как проверить
Проверьте, что пакет существует, поддерживается, с понятной лицензией и точным именем (без опечаток); нельзя ли обойтись уже подключёнными.

CR-ARC-002

Что ищем
Зависимости изменены, lock-файл — нет
Как обнаруживается
В манифесте добавлены или изменены зависимости, а соответствующего lock-файла (package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, go.sum, Cargo.lock, Gemfile.lock, composer.lock…) в diff нет.
Важность
средняя
Как проверить
Обновите lock-файл тем же менеджером пакетов и закоммитьте его вместе с манифестом.

CR-ARC-003

Что ищем
Серверный модуль импортируется в клиентский компонент (пакет: Next.js App Router)
Как обнаруживается
В файле с "use client" добавлен импорт server-only, next/headers, fs, child_process, node:*, @prisma/client, pg, mysql2, mongoose, bcrypt, nodemailer, firebase-admin, stripe.
Важность
высокая
Как проверить
Перенесите работу с модулем в серверный компонент, route handler или server action и передайте в клиент только данные.

CR-ARC-004

Что ищем
Непубличная переменная окружения в клиентском компоненте (пакет: Next.js App Router)
Как обнаруживается
process.env.X без префикса NEXT_PUBLIC_ (кроме NODE_ENV) в файле с "use client".
Важность
средняя
Как проверить
Если значение секретное — читайте его на сервере. Если публичное — переименуйте с префиксом NEXT_PUBLIC_.
Архитектура

CR-REL-001

Что ищем
Ошибка перехватывается и молча игнорируется
Как обнаруживается
Пустой catch {} (в одной строке или catch (…) { и следующая строка «}»), .catch(() => {}), except: pass / except Exception: pass (в одной или двух строках), пустой if err != nil {} в Go.
Важность
средняя
Как проверить
Обработайте ошибку явно: лог с контекстом, повтор, сообщение пользователю или проброс дальше. Если игнорирование задумано — оставьте комментарий.

CR-REL-002

Что ищем
Адрес localhost или внутренний IP в коде
Как обнаруживается
http(s)://localhost, 127.0.0.1, 0.0.0.0, [::1], 10.x, 192.168.x, 172.16–31.x в добавленных строках кода (кроме тестов). Если рядом process.env/os.environ — уверенность низкая.
Важность
низкая
Как проверить
Вынесите адрес в переменную окружения или конфигурацию и проверьте значение для каждого окружения.
Надёжность

CR-MNT-001

Что ищем
Очень большое изменение в одном файле
Как обнаруживается
Больше 400 добавленных строк в одном файле кода (кроме тестов и сгенерированных файлов).
Важность
низкая
Как проверить
Разбейте изменение на логические части или проведите ревью по разделам; проверьте на дубли с существующим кодом.

CR-MNT-002

Что ищем
Добавлен TODO / FIXME / HACK
Как обнаруживается
Слова TODO, FIXME, HACK, XXX (заглавными) в добавленных строках кода.
Важность
информация
Как проверить
Проверьте, что пометка не прячет недоделанную логику; заведите задачу или доделайте до слияния.

CR-MNT-003

Что ищем
Отладочный вывод или точка останова
Как обнаруживается
console.log/debug/trace/dir, debugger, print( в Python, breakpoint(), pdb.set_trace(), var_dump/print_r/dd, binding.pry, puts, System.out.print, printStackTrace, Console.Write — кроме тестов и каталогов scripts/, bin/, cli/, tools/.
Важность
низкая
Как проверить
Удалите или замените структурированным логированием с уровнем.

CR-MNT-004

Что ищем
Отключение проверки типов или линтера
Как обнаруживается
any / as any, @ts-ignore, @ts-expect-error, @ts-nocheck, eslint-disable, # type: ignore, # noqa, pylint: disable, //nolint, @SuppressWarnings, rubocop:disable, #pragma warning disable. @ts-nocheck и eslint-disable на весь файл — средняя важность.
Важность
низкая
Как проверить
Проверьте, можно ли описать тип точно или исправить причину предупреждения; оставьте комментарий, почему подавление нужно.

CR-MNT-005

Что ищем
Добавлен большой закомментированный блок кода
Как обнаруживается
5+ подряд добавленных строк-комментариев, похожих на код (; { } ( ) = или return/if/for/const/def/import в начале).
Важность
низкая
Как проверить
Удалите блок или объясните, зачем он оставлен.
Сопровождаемость

Очень большое изменение файла (CR-MNT-001)

Значение
больше 400 добавленных строк

Крупное обновление снимков (CR-TST-005)

Значение
200+ изменённых строк

Закомментированный код (CR-MNT-005)

Значение
5+ строк подряд

Замечаний одного правила в одном файле

Значение
до 20, остальные — счётчиком
Пороги

Тестовые файлы определяются по путям: tests/…, __tests__/…, e2e/…; login.test.ts, cart.spec.js; auth_test.go; test_auth.py, auth_test.py; AuthServiceTest.java; AuthTests.cs; user_spec.rb; UserTest.php; LoginTests.swift; __snapshots__/x.snap.

Ограничения

  • Код не выполняется; строки diff сопоставляются с шаблонами. Шаблоны могут пропустить проблему (например, SQL, собранный в нескольких строках) или сработать ложно.
  • Связи между файлами, типы и поток данных не анализируются: правило видит строку, а не программу. Файлы вне diff не учитываются.
  • Это не замена SAST, тестам и инженерному ревью — это быстрый первый проход с доказательствами, который помогает не пропустить типичные ошибки.

Приватность

  • Diff разбирается в вашем браузере: код не отправляется на сервер и не попадает в адрес страницы.
  • Черновик, решения и версии хранятся только в этом браузере (localStorage); «Очистить всё» удаляет их.
  • В доказательствах и экспорте значения, похожие на секреты, заменяются на [REDACTED]; перед экспортом показывается предупреждение.
  • В аналитику уходит только факт ревью или экспорта и категория (наибольшая важность, формат файла) — без кода и путей.
  • Результат уходит к нам, только если вы сами оставите заявку и не снимете галочку «Приложить результат» — что именно уйдёт, видно в форме. В сводке — счётчики и правило · файл:строка · заголовок, без кода.

Похожие инструменты

Все инструменты · 40
Самопроверка зрелости MVP16 вопросов о коде, доступах, данных, тестах и релизах. Покажет, что проверить в первую очередь, — без оценок «из 100» и без регистрации.Context Vault: контекст проектаДокументы, решения и ограничения проекта в одном месте: поиск по источникам, контроль устаревания и контекстные пакеты под задачу для AI-агента или нового разработчика.Spec Drift Detector: код против ТЗТребования ↔ изменения Git/PR: карта трассируемости, вероятные расхождения, изменения без требований и требования без тестовых доказательств — с разбором ревьюером.Project Handoff: передача проектаСнимок репозитория, архитектура, прогресс, блокеры, риски, тесты и следующие задачи → проверяемый пакет передачи для разработчика или AI-агента.Учёт расходов на AI-агентовИмпорт событий API (CSV/JSONL) → токены и затраты по проектам, моделям и задачам, повторные попытки, бюджеты и предупреждения. Цены — из вашего прайса.Готовность к релизуМатрица проверок с доказательствами: CI, миграции, резервные копии, план отката, мониторинг, исключения из рисков и согласование → решение GO / NO-GO.
Расскажите о задаче — мы изучим запрос и свяжемся с вами

Нужно ревью кода, написанного с AI-агентами?

Аудит кода: доступы и роли, секреты, база данных и RLS, API, тесты и деплой — с картой рисков и планом исправлений. Первый короткий разговор бесплатный; объём и стоимость — после брифа.

  • Первый короткий разговор бесплатный — выбираем формат работы
  • NDA — по вашему или нашему шаблону
  • Стоимость — после брифа и согласования объёма

Не присылайте через форму пароли, ключи доступа и исходный код — безопасную передачу доступа обсудим отдельно.

Нажимая кнопку, вы соглашаетесь с обработкой персональных данных.