Сервер ревью: доступ команде без раздачи ключа
Ревью в редакторе требует ключа LLM. Раздавать корпоративный ключ двадцати разработчикам никто не хочет, а свой купят единицы — и вторая точка контроля остаётся у меньшинства команды. Сервер ревью решает это: ключ остаётся на вашем сервере, разработчик получает личный доступ к нему.
Как это работает
Бинарь на машине разработчика собирает изменения обычным git и отправляет их вашему серверу ReviewGate — тому же, что проверяет MR/PR. Ревью выполняет он: своим ключом, своей моделью, через свою сеть. Разработчику ключ не нужен и не выдаётся.
Что включить на сервере
Шесть переменных окружения. Пока первая не задана, режим выключен целиком — это запрет по умолчанию, а не забывчивость: сервер не начнёт принимать прогоны сам собой после обновления.
# GitLab groups that grant access to the review server (comma-separated, full paths).
# Empty or unset — the mode is off and CLI runs are not accepted.
REVIEWGATE_CLI_GROUPS=dev/reviewgate-cli
# How many reviews the server runs at once. The mode needs at least 2.
REVIEW_CONCURRENCY=4
# How many of those may be taken by developers working locally.
# Half by default; must be strictly less than REVIEW_CONCURRENCY.
REVIEW_CLI_CONCURRENCY=2
# Session timings — rarely worth changing; the values below are the defaults.
# How long a run waits for a free slot before it is refused with «the server is busy».
REVIEW_CLI_QUEUE_WAIT_MS=60000
# Waiting for ONE file from the developer machine. Deliberately shorter than the session cap:
# the slot is held while the server waits, and a sleeping laptop would otherwise eat capacity.
REVIEW_CLI_FILE_TIMEOUT_MS=30000
# The lifetime cap of a session. A full run with an ensemble and an arbiter takes ~5 minutes.
REVIEW_CLI_SESSION_TIMEOUT_MS=900000Пул для разработчиков ограничен сверху, и разница с общей ёмкостью — ваш резерв: столько проверок MR/PR стартует немедленно, что бы разработчики ни делали локально. Гейт не встанет в очередь за чужими прогонами. Сервер печатает эту гарантию словами при старте и отдаёт её же в /api/health.
Там же видно, кто занимает слоты прямо сейчас — это первое, что стоит посмотреть на жалобу «CLI отвечает, что сервер занят»: идёт ли проверка MR/PR, висит ли чужой прогон или ёмкости просто мало.
curl -s http://localhost:3000/api/health
# {"status":"ok", ... "capacity":{
# "total":4,"cli":2,"mrReserve":2, <- the configuration
# "inFlight":{"mr":1,"cli":2}, <- busy right now
# "waiting":1 <- waiting for a slot
# }}В журнале сервера такие отказы — предупреждения, а не ошибки: сработавшая политика ёмкости не должна теряться среди настоящих сбоев.
Чем управляет разработчик, а чем вы
Ревью выполняется по политике из рабочей копии разработчика — так задумано: человек правит .reviewgate/config.yml и сразу видит эффект, не коммитя. Но стоит знать обратную сторону: в этом файле задаются модель, второй проход и состав ансамбля, а платит за них ключ инсталляции. Незакоммиченная правка «поставлю себе модель помощнее» увеличивает счёт компании, и сервер её не оспаривает.
Кому можно — решается в GitLab
Доступ выдаётся членством в группе GitLab, а не отдельным списком у нас. Добавили человека в группу — доступ есть. Убрали — нет. Заблокировали учётную запись при увольнении — доступ закрылся сам, без отдельного действия администратора.
Групп можно указать несколько: например, отдельную для тех, кому доступ шире. Проверяется членство с наследованием — доступ, выданный на верхнюю группу, работает и в подгруппах.
Что можно ревьюить
Бинарь сообщает адрес origin своего репозитория, а сервер проверяет через API вашего GitLab, что такой проект у вас есть и у этого человека к нему доступ уровня Reporter или выше. Личный проект на стороннем хостинге проверку не пройдёт: корпоративный ключ тратится на ваш код, а не на что угодно.
Сервер принимает только запросы на ревью и отвечает списком находок. Это не прокси к языковой модели: вести через него диалог или получать произвольный текст нельзя.
Что видно вам
Каждый прогон попадает в журнал сервера: кто (логин GitLab), какой проект, сколько файлов и в каком режиме — там же, где остальные логи бота (логи и мониторинг). Кто сколько проверок сделал, видно по журналу.
Брошенный прогон денег не тратит: если разработчик прервал команду или потерял связь, сервер прекращает вызовы моделей — уже начатый ответ провайдер, скорее всего, посчитает, но следующие шаги (второй генератор, судья) не начинаются. В журнале такой прогон виден как отменённый, в метриках — со статусом cancelled.
Расход тоже виден: каждый прогон CLI пишет строку в те же метрики Postgres, что и проверки MR/PR — с логином разработчика, проектом, моделями и токенами по ролям. Запрос «кто сколько потратил за месяц» есть готовым на той же странице. Метрики включаются заданием DATABASE_URL; без него бот работает, но учёта не будет.
Что делает разработчик
Ставит бинарь (CLI, хук и MCP) и создаёт один файл в своём домашнем каталоге:
server:
url: https://bot.вашакомпания.ru
gitlab_token: glpat-... # the developer's personal GitLab tokenТокен — обычный personal access token GitLab самого разработчика, тот же, которым он ходит в GitLab. Ключ модели ему не нужен. Проверить готовность рабочего места:
reviewgate doctorКоманда скажет, есть ли доступ: назовёт логин разработчика и путь проекта, который увидел сервер, — либо причину отказа (токен не принят, нет доступа к репозиторию, нет сети). Занятость сервера она не проверяет: это состояние минуты, и узнаётся оно на самом прогоне — отказом «попробуйте позже», а не отказом в доступе.