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). См. раздел раздел безопасности ниже.


Предварительные условия


Шаг 1. Включите платформу веб-перехватчиков

Добавьте следующее в свой ~/.hermes/config.yaml:

platforms:
  webhook:
    enabled: true
    extra:
      port: 8644          # default; change if another service occupies this port
      rate_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 exactly
          events:
            - 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_comment
          deliver_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` по умолчанию, поэтому дополнительная настройка не требуется.

Шаг 2 — Запустите шлюз

hermes gateway

Вы должны увидеть:

[webhook] Listening on 0.0.0.0:8644  routes: github-pr-review

Убедитесь, что он работает:

curl http://localhost:8644/health
# {"status": "ok", "platform": "webhook"}

Шаг 3 — Зарегистрируйте вебхук на GitHub

  1. Перейдите в свой репозиторий → НастройкиВебхукиДобавить вебхук.
  2. Заполните:
  3. URL полезной нагрузки: https://your-public-url.example.com/webhooks/github-pr-review
  4. Content type: application/json
  5. Secret: the same value you set for secret in the route config
  6. Which events? → Select individual events → check Pull requests
  7. 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.

To follow the agent's progress in real time:

tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"

Local testing with ngrok

If Hermes is running on your laptop, use ngrok to expose it:

ngrok http 8644

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`, как только вы будете удовлетворены быстрым выводом.
SECRET="your-webhook-secret-here"
BODY='{"action":"opened","number":99,"pull_request":{"title":"Test PR","body":"Adds a feature.","user":{"login":"testuser"},"head":{"ref":"feat/x"},"base":{"ref":"main"},"html_url":"https://github.com/org/repo/pull/99"},"repository":{"full_name":"org/repo"}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print "sha256="$2}')

curl -s -X POST http://localhost:8644/webhooks/github-pr-review \
  -H "Content-Type: application/json" \
  -H "X-GitHub-Event: pull_request" \
  -H "X-Hub-Signature-256: $SIG" \
  -d "$BODY"
# Expected: {"status":"accepted","route":"github-pr-review","event":"pull_request","delivery_id":"..."}

Затем посмотрите, как работает агент:

tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"

:::примечание 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: true
    extra:
      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:
            - review
          deliver: github_comment
          deliver_extra:
            repo: "{repository.full_name}"
            pr_number: "{number}"

Примечание. Загружается только первый найденный навык в списке. Гермес не объединяет несколько навыков — последующие записи игнорируются.


Вместо этого отправка ответов в Slack или Discord

Замените поля deliver и deliver_extra внутри вашего маршрута на вашу целевую платформу:

# Inside platforms.webhook.extra.routes.<route-name>:

# Slack
deliver: slack
deliver_extra:
  chat_id: "C0123456789"   # Slack channel ID (omit to use the configured home channel)

# Discord
deliver: discord
deliver_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) будет описывать ее структуру.


Примечания по безопасности


Устранение неполадок

Симптом Проверить
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: true
    extra:
      host: "0.0.0.0"         # bind address (default: 0.0.0.0)
      port: 8644               # listen port (default: 8644)
      secret: ""               # optional global fallback secret
      rate_limit: 30           # requests per minute per route
      max_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 values
          prompt: ""            # {field} / {nested.field} resolved from payload
          skills: []            # first matching skill is loaded (only one)
          deliver: "log"        # log | github_comment | telegram | discord | slack | signal | sms
          deliver_extra: {}     # repo + pr_number for github_comment; chat_id for others

Что дальше?