Обработка вебхуков GitHub на serverless для CI/CD и автоматизации
Вебхуки GitHub срабатывают на push, pull_request, release, issues и другие события. Соберите serverless-обработчик, который проверяет HMAC-SHA256, маршрутизирует события по типу и запускает асинхронные пайплайны для CI/CD, индексации репозитория и автоматизации issues.
Обновлено: 2026-06-28
Кратко
Суть ответа
Обработка вебхуков GitHub на serverless для CI/CD и автоматизации. Одна функция проверяет подпись и направляет события по типу в отдельные задачи пайплайна. События push запускают индексацию, pull_request — автоматизацию ревью, release — пайплайны деплоя.
Когда подходит
- Триггеры CI/CD на события push и PR
- Индексация репозитория, синхронизация документации и обновление поискового индекса по push
- Автоматическая разметка issues, запросы ревью PR и деплой релизов
На что обратить внимание
- Если индексация репозитория, расчёт эмбеддингов или запуск CI-задач выполняются синхронно до ответа, любая задержка в этих системах заставит GitHub повторить доставку на ваш эндпоинт.
- Обработка всех типов событий в одном обработчике создаёт монолит, который сложно тестировать, сложно деплоить и легко сломать.
Нагрузка и где ломается
Где ломается обработка вебхуков GitHub
- HMAC-SHA256 с timing-safe сравнением — стандарт, в котором легко ошибиться
- Десятки типов событий в одном эндпоинте — логика маршрутизации быстро разрастается
- Тяжёлая работа (индексация, запуск CI) в окне вебхука приводит к таймаутам доставки GitHub
GitHub повторяет неудачные доставки до 3 дней. Без быстрого ACK и идемпотентной обработки одна и та же CI-задача может запуститься, а один и тот же коммит — проиндексироваться несколько раз.
Когда простых рецептов недостаточно
Почему обработка событий GitHub внутри запроса хрупка
Если индексация репозитория, расчёт эмбеддингов или запуск CI-задач выполняются синхронно до ответа, любая задержка в этих системах заставит GitHub повторить доставку на ваш эндпоинт.
Обработка всех типов событий в одном обработчике создаёт монолит, который сложно тестировать, сложно деплоить и легко сломать.
Как помогает Inquir
Проверить, направить, разветвить: паттерн вебхука GitHub
Одна функция проверяет подпись и направляет события по типу в отдельные задачи пайплайна. События push запускают индексацию, pull_request — автоматизацию ревью, release — пайплайны деплоя.
Что вы получаете
Что нужно для обработки вебхуков GitHub
Timing-safe проверка HMAC-SHA256
Используйте crypto.timingSafeEqual — никогда не сравнение строк, — чтобы исключить атаки по времени на проверку подписи.
Маршрутизация по типу события
Заголовок x-github-event определяет событие. Направляйте разные типы событий в разные функции пайплайна.
Дедупликация по ID доставки
Используйте заголовок x-github-delivery как ключ идемпотентности, чтобы при повторной доставке пропускать уже обработанные события.
Асинхронное разветвление
Одно событие push может запустить параллельные пайплайны: проиндексировать документацию, прогнать линтер, обновить поиск, уведомить Slack.
Что дальше
Поток обработки вебхука GitHub
Проверить HMAC-SHA256 timing-safe
Извлеките x-hub-signature-256, посчитайте ожидаемый HMAC, сравните через timingSafeEqual.
Направить по типу события, вернуть 200
Сделайте switch по заголовку x-github-event. Запустите нужный пайплайн. Ответьте быстро — не дожидаясь завершения пайплайнов.
Обработать в пайплайнах
Каждый шаг пайплайна выполняется независимо, с ретраями. Ключи дедупликации не дают обработать событие дважды при повторной доставке.
Пример кода
Обработчик вебхуков GitHub для push и PR
Проверить HMAC, направить по типу события, запустить асинхронные пайплайны — всё до ответа 200 для GitHub.
import { createHmac, timingSafeEqual } from 'node:crypto'; export async function handler(event) { const body = event.body ?? ''; const sigHeader = (event.headers['x-hub-signature-256'] ?? '').replace('sha256=', ''); const expected = createHmac('sha256', process.env.GITHUB_WEBHOOK_SECRET).update(body).digest('hex'); if (sigHeader.length !== expected.length || !timingSafeEqual(Buffer.from(sigHeader, 'hex'), Buffer.from(expected, 'hex'))) { return { statusCode: 401, body: 'invalid signature' }; } const eventType = event.headers['x-github-event']; const deliveryId = event.headers['x-github-delivery']; const payload = JSON.parse(body); const isNew = await db.webhookDeliveries.upsert(deliveryId); if (!isNew) return { statusCode: 200, body: 'duplicate' }; if (eventType === 'push') { await global.durable.startNew('index-repo', undefined, { repo: payload.repository.full_name, sha: payload.after }); } else if (eventType === 'pull_request' && payload.action === 'opened') { await global.durable.startNew('review-pr', undefined, { repo: payload.repository.full_name, pr: payload.number }); } else if (eventType === 'release' && payload.action === 'published') { await global.durable.startNew('deploy-release', undefined, { repo: payload.repository.full_name, tag: payload.release.tag_name }); } return { statusCode: 200, body: 'accepted' }; }
Когда подходит
Используйте для автоматизации GitHub
Когда это уместно
- Триггеры CI/CD на события push и PR
- Индексация репозитория, синхронизация документации и обновление поискового индекса по push
- Автоматическая разметка issues, запросы ревью PR и деплой релизов
Когда лучше выбрать другое
- Простые воркфлоу GitHub Actions, которым не нужна внешняя serverless-обработка
Частые вопросы
Частые вопросы
Как тестировать локально?
Используйте gh webhook forward --repo owner/repo --events push --url http://localhost:PORT, чтобы пересылать реальные события в локальную функцию.
А события ревью pull_request?
GitHub присылает много под-действий (submitted, dismissed, edited). Всегда проверяйте payload.action, чтобы направить событие правильно.