sidebar_position: 11
sidebar_label: "GitHub PR Reviews via Webhook"
title: "Automated GitHub PR Comments with Webhooks"
description: "Connect Hermes to GitHub so it automatically fetches PR diffs, reviews code changes, and posts comments — triggered by webhooks with no manual prompting"
lang: ru
Автоматические PR-комментарии GitHub с помощью веб-хуков
В этом руководстве рассказывается, как подключить агент Hermes к GitHub, чтобы он автоматически получал разницу запроса на включение, анализировал изменения кода и публиковал комментарий, запускаемый событием веб-перехватчика, без ручного запроса.
Когда PR открывается или обновляется, GitHub отправляет POST веб-перехватчика на ваш экземпляр Hermes. Hermes запускает агент с приглашением, которое инструктирует его получить разницу через CLI gh, и ответ отправляется обратно в поток PR.
💡 Tip
Хотите более простую настройку без общедоступной конечной точки?
Если у вас нет общедоступного URL-адреса или вы просто хотите быстро приступить к работе, ознакомьтесь с [Создание агента PR-ревью GitHub](./github-pr-review-agent.md) — использует задания cron для опроса PR по расписанию, работает за NAT и брандмауэрами.
ℹ️ Info
Справочная документация
Полный справочник по платформе веб-перехватчиков (все параметры конфигурации, типы доставки, динамические подписки, модель безопасности) см. в разделе [Веб-перехватчики](/docs/user-guide/messaging/webhooks).
:::предупреждение: риск быстрого внедрения
Полезные данные вебхука содержат данные, контролируемые злоумышленниками: PR-заголовки, сообщения о фиксации и описания могут содержать вредоносные инструкции. Когда конечная точка вашего веб-перехватчика доступна в Интернете, запустите шлюз в изолированной среде (Docker, серверная часть SSH). См. раздел раздел безопасности ниже.
Предварительные условия
Агент Hermes установлен и работает (hermes gateway)
gh CLI установлен и аутентифицирован на узле шлюза (gh auth login)
Доступ администратора к репозиторию GitHub (требуется для управления веб-перехватчиками).
Шаг 1. Включите платформу веб-перехватчиков
Добавьте следующее в свой ~/.hermes/config.yaml:
platforms:webhook:enabled:trueextra:port:8644# default; change if another service occupies this portrate_limit:30# max requests per minute per route (not a global cap)routes:github-pr-review:secret:"your-webhook-secret-here"# must match the GitHub webhook secret exactlyevents:-pull_request# The agent is instructed to fetch the actual diff before reviewing.# {number} and {repository.full_name} are resolved from the GitHub payload.prompt:|A pull request event was received (action: {action}).PR #{number}: {pull_request.title}Author: {pull_request.user.login}Branch: {pull_request.head.ref} → {pull_request.base.ref}Description: {pull_request.body}URL: {pull_request.html_url}If the action is "closed" or "labeled", stop here and do not post a comment.Otherwise:1. Run: gh pr diff {number} --repo {repository.full_name}2. Review the code changes for correctness, security issues, and clarity.3. Write a concise, actionable review comment and post it.deliver:github_commentdeliver_extra:repo:"{repository.full_name}"pr_number:"{number}"
Ключевые поля:
Поле
Описание
secret (уровень маршрута)
Секрет HMAC для этого маршрута. Возвращается к глобальному значению extra.secret, если оно опущено.
events
Список значений заголовка X-GitHub-Event, которые можно принять. Пустой список = принять все.
prompt
Шаблон; {field} и {nested.field} разрешаются из полезных данных GitHub.
deliver
github_comment сообщения через gh pr comment. log просто записывает в журнал шлюза.
deliver_extra.repo
Решает, например, org/repo из полезной нагрузки.
deliver_extra.pr_number
Преобразуется в номер PR из полезной нагрузки.
📝 Note
Полезная нагрузка не содержит кода
Полезная нагрузка веб-перехватчика GitHub включает метаданные PR (заголовок, описание, названия ветвей, URL-адреса), но **не различия**. Приведенная выше подсказка предписывает агенту запустить `gh pr diff` для получения фактических изменений. Инструмент `terminal` включен в набор инструментов `hermes-webhook` по умолчанию, поэтому дополнительная настройка не требуется.
Secret: the same value you set for secret in the route config
Which events? → Select individual events → check Pull requests
Click Add webhook
GitHub will immediately send a ping event to confirm the connection. It is safely ignored — ping is not in your events list — and returns {"status": "ignored", "event": "ping"}. It is only logged at DEBUG level, so it won't appear in the console at the default log level.
Step 4 — Open a test PR
Create a branch, push a change, and open a PR. Within 30–90 seconds (depending on PR size and model), Hermes should post a review comment.
If Hermes is running on your laptop, use ngrok to expose it:
ngrokhttp8644
Copy the https://...ngrok-free.app URL-адрес и используйте его как URL-адрес полезной нагрузки GitHub. На бесплатном уровне ngrok URL-адрес меняется каждый раз при перезапуске ngrok — обновляйте веб-хук GitHub при каждом сеансе. Платные аккаунты ngrok получают статический домен.
Вы можете протестировать статический маршрут напрямую с помощью curl — никакой учетной записи GitHub или реального пиара не требуется.
💡 Tip
Используйте `deliver: log` при локальном тестировании.
Измените `deliver: github_comment` на `deliver: log` в вашей конфигурации во время тестирования. В противном случае агент попытается опубликовать комментарий к поддельному репозиторию `org/repo#99` в тестовых полезных данных, но это не удастся. Вернитесь к `deliver: github_comment`, как только вы будете удовлетворены быстрым выводом.
:::примечание
hermes webhook test <name> работает только для динамических подписок, созданных с помощью hermes webhook subscribe. Маршруты от config.yaml он не читает.
Фильтрация по конкретным действиям
GitHub отправляет события pull_request для многих действий: opened, synchronize, reopened, closed, labeled и т. д. Список events фильтрует только по значению заголовка X-GitHub-Event — он не может фильтровать по подтипу действия на уровне маршрутизации.
Подсказка на шаге 1 уже обрабатывает эту проблему, предписывая агенту досрочно остановиться для событий closed и labeled.
⚠️ Warning
Агент все еще работает и потребляет токены
Инструкция «остановить здесь» препятствует полноценной проверке, но агент по-прежнему работает до завершения для каждого события `pull_request` независимо от действия. Веб-перехватчики GitHub могут фильтровать только по типу событий (`pull_request`, `push`, `issues` и т. д.), а не по подтипу действия (`opened`, `closed`, `labeled`). Для дополнительных действий фильтр уровня маршрутизации отсутствует. Для репозиториев большого объема примите эту стоимость или отфильтруйте исходящие данные с помощью рабочего процесса GitHub Actions, который условно вызывает URL-адрес вашего веб-перехватчика.
Не существует синтаксиса Jinja2 или условного шаблона. {field} и {nested.field} — единственные поддерживаемые замены. Все остальное передается агенту дословно.
Использование навыков для последовательного стиля обзора
Загрузите навык Hermes, чтобы предоставить агенту единообразный образ проверки. Добавьте skills в свой маршрут внутри platforms.webhook.extra.routes в config.yaml:
platforms:webhook:enabled:trueextra:routes:github-pr-review:secret:"your-webhook-secret-here"events:[pull_request]prompt:|A pull request event was received (action: {action}).PR #{number}: {pull_request.title} by {pull_request.user.login}URL: {pull_request.html_url}If the action is "closed" or "labeled", stop here and do not post a comment.Otherwise:1. Run: gh pr diff {number} --repo {repository.full_name}2. Review the diff using your review guidelines.3. Write a concise, actionable review comment and post it.skills:-reviewdeliver:github_commentdeliver_extra:repo:"{repository.full_name}"pr_number:"{number}"
Примечание. Загружается только первый найденный навык в списке. Гермес не объединяет несколько навыков — последующие записи игнорируются.
Вместо этого отправка ответов в Slack или Discord
Замените поля deliver и deliver_extra внутри вашего маршрута на вашу целевую платформу:
# Inside platforms.webhook.extra.routes.<route-name>:# Slackdeliver:slackdeliver_extra:chat_id:"C0123456789"# Slack channel ID (omit to use the configured home channel)# Discorddeliver:discorddeliver_extra:chat_id:"987654321012345678"# Discord channel ID (omit to use home channel)
Целевая платформа также должна быть включена и подключена к шлюзу. Если chat_id опущено, ответ отправляется на настроенный домашний канал этой платформы.
Допустимые значения deliver: log · github_comment · telegram · discord · slack · signal · sms
Поддержка GitLab
Этот же адаптер работает с GitLab. GitLab использует X-Gitlab-Token для аутентификации (соответствие простой строки, а не HMAC) — Hermes обрабатывает и то, и другое автоматически.
Для фильтрации событий GitLab устанавливает для X-GitLab-Event такие значения, как Merge Request Hook, Push Hook, Pipeline Hook. Используйте точное значение заголовка в events:
events:-Merge Request Hook
Поля полезной нагрузки GitLab отличаются от полей GitHub — например. {object_attributes.title} для названия MR и {object_attributes.iid} для номера MR. Самый простой способ узнать полную структуру полезных данных — это нажать кнопку Тест в GitLab в настройках веб-перехватчика в сочетании с журналом Последние поставки. Альтернативно, опустите prompt в конфигурации маршрута — тогда Hermes передаст полную полезную нагрузку в формате JSON непосредственно агенту, и ответ агента (видимый в журнале шлюза с deliver: log) будет описывать ее структуру.
Примечания по безопасности
Никогда не используйте INSECURE_NO_AUTH в производстве — это полностью отключает проверку подписи. Это только для местного развития.
Периодически меняйте секрет веб-перехватчика и обновляйте его как на GitHub (настройки веб-перехватчика), так и на своем config.yaml.
Ограничение скорости по умолчанию составляет 30 запросов/мин на маршрут (настраивается через extra.rate_limit). При его превышении возвращается 429.
Дубликаты поставок (повторные попытки веб-перехватчика) дедуплицируются с помощью 1-часового идемпотентного кеша. Ключ кэша: X-GitHub-Delivery, если он присутствует, затем X-Request-ID, а затем миллисекундная метка времени. Если ни один из заголовков идентификатора доставки не задан, повторные попытки не дедуплицируются.
Быстрое внедрение: PR-заголовки, описания и сообщения о фиксации контролируются злоумышленниками. Злонамеренные пиарщики могут попытаться манипулировать действиями агента. Запускайте шлюз в изолированной среде (Docker, виртуальная машина) при наличии доступа к общедоступному Интернету.
Устранение неполадок
Симптом
Проверить
401 Invalid signature
Секрет в config.yaml не соответствует секрету веб-перехватчика GitHub
404 Unknown route
Имя маршрута в URL-адресе не соответствует ключу в routes:
429 Rate limit exceeded
Превышено 30 запросов в минуту на каждый маршрут — обычно при повторной доставке тестовых событий из пользовательского интерфейса GitHub; подождите минутку или поднимите extra.rate_limit
Комментариев не оставлено
gh не установлен, не находится в PATH или не прошел проверку подлинности (gh auth login)
Агент запускается, но комментариев нет
Проверьте журнал шлюза — если выходные данные агента были пустыми или просто «ПРОПУСТИТЬ», попытка доставки все равно будет
Порт уже используется
Измените extra.port в config.yaml
Агент работает, но просматривает только описание PR
Приглашение не включает инструкцию gh pr diff — разница отсутствует в полезных данных веб-перехватчика
Не могу увидеть событие ping
Игнорированные события возвращают {"status":"ignored","event":"ping"} только на уровне журнала DEBUG — проверьте журнал доставки GitHub (репозиторий → Настройки → Веб-перехватчики → ваш веб-перехватчик → Недавние поставки)
Вкладка «Последние доставки» GitHub (репозиторий → Настройки → Веб-перехватчики → ваш веб-перехватчик) показывает точные заголовки запросов, полезные данные, статус HTTP и тело ответа для каждой доставки. Это самый быстрый способ диагностировать сбои, не затрагивая журналы сервера.
Полная ссылка на конфигурацию
platforms:webhook:enabled:trueextra:host:"0.0.0.0"# bind address (default: 0.0.0.0)port:8644# listen port (default: 8644)secret:""# optional global fallback secretrate_limit:30# requests per minute per routemax_body_bytes:1048576# payload size limit in bytes (default: 1 MB)routes:<route-name>:secret:"required-per-route"events:[]# [] = accept all; otherwise list X-GitHub-Event valuesprompt:""# {field} / {nested.field} resolved from payloadskills:[]# first matching skill is loaded (only one)deliver:"log"# log | github_comment | telegram | discord | slack | signal | smsdeliver_extra:{}# repo + pr_number for github_comment; chat_id for others