2026 OpenClaw: вебхук шлюза, GitHub и проверка подписи на macOS

Когда вы подключаете вебхуки репозитория GitHub к шлюзу в духе OpenClaw на удалённом Mac, большинство сбоев оказываются не «магией Git», а инфраструктурой: публичный URL не совпадает с тем, что вы тестировали с ноутбука, тело, которое вы хэшируете, уже не то же самое, что подписал GitHub, а процесс успевает «проснуться» позже, чем воркер доставки помечает таймаут. Этот текст — воспроизводимый учебник по TLS-входу, заголовкам HMAC, часам и двум самым громким симптомам: 401 и таймаутам доставки. Держите слушатель здоровым через материал 2026 OpenClaw: справочник по стабильности шлюза в launchd — сверка doctor/status/logs, порты и конфликт двух LaunchAgent на удалённом постоянно включённом Mac, а поведение Actions и диска согласуйте с 2026 OpenClaw: пошаговое развёртывание и интеграция с автоматизацией — офлайн‑устойчивость кроссплатформенных агентов, права выполнения и совместная работа нескольких runner в GitHub Actions, чтобы задания, которые стартуют по вебхуку, не зависали на I/O раньше, чем ответят HTTP.

1. Зафиксируйте воспроизводимый публичный callback до ротации секретов

GitHub вызывает вас только из публичного интернета. Неважно, терминируете ли вы TLS на nginx, балансировщике или туннеле вроде Cloudflare Tunnel / ngrok: выпишите имя хоста, префикс пути и то, обрезает ли край заголовки или тело. Воспроизведите curl -v https://ваш-хост/ваш-путь снаружи LAN, а не с самого Mac: успех на loopback часто скрывает неправильный SNI или hairpin NAT. Если reverse proxy буферизует тело, приложение должно читать те же сырые байты, которые подписал GitHub — иначе любая проверка подписи падает при верном секрете. Держите один канонический URL в инфраструктуре и вставляйте ту же строку в настройки GitHub.

Правило дымового теста: если curl из интернета не попадает в ожидаемый быстрый ACK-путь шлюза, чините вход до очередной смены секрета вебхука.

2. Подпись и метка времени в контракте GitHub

GitHub подписывает сырое тело POST секретом вебхука через HMAC-SHA256 и кладёт результат в X-Hub-Signature-256. Хэшируйте тот же поток байтов после TLS, сравнивайте константным по времени алгоритмом и отбрасывайте некорректные префиксы sha256=. Добавьте политику допустимого сдвига часов: включите NTP на Mac, чтобы валидные подписи не отвергались рядом с короткоживущими bearer-проверками, а идентификаторы доставки используйте как ключи идемпотентности, чтобы повтор после таймаута не удваивал побочные эффекты.

Для защиты от повторного воспроизведения храните последний обработанный X-GitHub-Delivery или пару (event_id, delivery) в быстром хранилище с TTL и отклоняйте дубликаты до бизнес-логики. Логируйте минимальный набор заголовков без секретов: имя события, идентификатор доставки, код ответа и длительность обработки — этого достаточно, чтобы за минуту отличить «подпись не сошлась» от «апстрим GitHub API вернул 403 из-за истёкшего токена приложения».

3. Циклы 401: где рвётся доверие между краем и процессом

Частый сценарий — двойная аутентификация: край требует Basic или mTLS, а приложение ещё раз ждёт токен из другого заголовка. GitHub не умеет «догадываться» о вашем бастионе: либо оставьте публичный путь без лишних 401 с быстрым ответом для проверки подписи, либо вынесите проверку на уровень, который видит сырой запрос. Проверьте, что middleware не переписывает тело до HMAC, и что секрет в Keychain/файле совпадает с последним сохранением в GitHub — после ротации секрета старые доставки закономерно получают 401, пока вы не обновите обе стороны.

Ещё один источник «ложных» 401 — несовпадение пути из-за завершающего слэша или редиректа с 301, который превращает POST в GET на промежуточном прокси. Зафиксируйте канонический путь в конфиге края и убедитесь, что GitHub попадает в тот же location, что и ваши ручные curl-проверки.

4. Таймауты доставки и холодный старт на macOS

GitHub ждёт ответ десятки секунд; если ваш шлюз поднимается через launchd только после первого пакета или тянет тяжёлые зависимости при старте, внешний наблюдатель увидит таймаут раньше, чем ваш код успеет ответить 2xx. Держите процесс тёплым, ограничьте синхронные вызовы к GitHub API внутри обработчика вебхука и вынесите долгую работу в очередь с немедленным ACK. На удалённом Mac проверьте, что диск не забит артефактами CI — иначе даже лёгкий обработчик начнёт блокироваться на записи логов.

5. Чеклист для тикета — можно вставить как есть

  • Точный публичный URL из GitHub совпадает с тем, что даёт curl извне.
  • NTP включён; расхождение часов меньше пары минут.
  • HMAC считается по байтам тела до любых JSON-парсеров, которые могут нормализовать пробелы.
  • Нет второго слоя 401 между интернетом и обработчиком подписи.
  • Обработчик отвечает быстрым 2xx и не делает блокирующих вызовов к API GitHub в том же запросе.

Почему для такого шаблона по-прежнему выигрывают узлы класса Mac mini

Публичные колбэки не прощают дрожащее железо: каждый ложный таймаут превращается в шум пейджера. Mac mini на Apple Silicon сочетает сильную однопоточную производительность с очень низким холостым потреблением, поэтому круглосуточные демоны обходятся дешевле, чем простаивающая башня. Тот же стек нативного Unix, Homebrew и macOS с Gatekeeper, SIP и FileVault делает постоянный выход в интернет менее «самодельным», чем на типовых ПК. Если вы стандартизируете автоматизацию OpenClaw в 2026 году, начните с железа, которое тихо, предсказуемо и экономно простаивает; когда понадобится больше региональных нод, сравните модели на главной странице Macstripe, прежде чем покупать ядра, которые сеть никогда не насытит.

Если хотите прогнать именно этот runbook на самом плавном базовом железе, Mac mini M4 — сбалансированная стартовая точка: компактный корпус, тихое охлаждение и запас по CPU для шлюза и соседних CI-задач без превращения стойки в обогреватель. Когда будете готовы оценить выделенную ноду рядом с пулом self-hosted, откройте главную страницу Macstripe и сравните конфигурации под вашу нагрузку.