launchd, токен на endpoint, /health. См. установка, health LaunchAgent, retry.
- Две версии Node: SSH и
launchdс разными major — падает CLI или плагины. - Webhook без секрета/HMAC: открытый префлайт и утечки в логах.
- Нет коллбэка: обрыв TLS — префлайт прошёл, Jenkins «не знает».
Среда и минимальные привилегии: Node, токен и health
Node 22.16+ или 24 LTS — одинаково в SSH и в launchd после openclaw onboard и openclaw doctor; сверьте which node в обоих контекстах. В 2026 году большинство инструкций OpenClaw ориентируют шлюз на свежую LTS, поэтому закрепите версию в runbook и запретите «тихие» обновления через Homebrew без согласования.
Отдельный пользователь Mac, только WORK_ROOT и кеши Composer/npm; не смешивайте домашний каталог администратора с рабочими клонами. Bearer-токен для приватного HTTP-маршрута храните в Jenkins Credentials и в Keychain или env на Mac вне Git с chmod 600. Health к /health или корню Dashboard раз в минуту с алертом; при корпоративном MITM задайте единые HTTPS_PROXY, NO_PROXY и при необходимости NODE_EXTRA_CA_CERTS для curl и Node.
| Критерий | Рекомендуется | Избегать |
|---|---|---|
| Node на шлюзе | Одна LTS-версия в shell и в LaunchAgent | Разные major между ssh и сервисом |
| Доступ к endpoint | Bearer-токен + опционально allowlist IP | Публичный URL без аутентификации |
| Наблюдаемость | Логи шлюза с request_id и ротацией | Полные тела webhook в общий лог |
- onboard, Dashboard, порт bind.
- LaunchAgent:
PATH→ нужныйnode. curl -fsSна health;launchctl kickstart -kпосле ротации секретов.WORK_ROOT+ shallow clone.
Jenkins Generic Webhook и параметры проверки подписи
Generic Webhook Trigger: токен в URL job; SCM шлёт application/json с секретом репозитория (GitHub) или verify token (GitLab). Извлекайте ветку и SHA через JSONPath или regexp, чтобы не запускать префлайт на каждый тег или draft.
Минимально: общий секрет в заголовке X-Webhook-Token или в query, совпадающий с переменной на шлюзе OpenClaw. Если endpoint доступен извне, добавьте HMAC-SHA256 сырого тела в отдельном заголовке и проверку времени жизни подписи.
Из Jenkins в сторону Mac используйте httpRequest или curl с --connect-timeout 5 и --max-time 30; тело JSON с полями job, build, ref, correlation_id для склейки логов на шлюзе и в Jenkins.
| Механизм | Плюс | Минус |
|---|---|---|
| Секрет только в URL | Простая настройка за пять минут | Утечка в access-логах прокси |
| HMAC заголовок | Тело не подделать без ключа | Нужен общий код на SCM и шлюзе |
| mTLS к шлюзу | Сильная идентификация клиента | Операционные затраты на сертификаты |
OpenClaw: приём webhook и шаблоны префлайта composer и npm
После проверки токена выполните git clone --depth 1 в WORK_ROOT на нужный ref; при внутренних зеркалах экспортируйте COMPOSER_REPO_PACKAGIST и NPM_CONFIG_REGISTRY до вызова CLI. Полный JSON webhook в лог не пишите — храните correlation_id и короткий список изменённых путей.
PHP: composer validate --no-check-publish --no-interaction, затем composer install --no-dev --no-interaction --prefer-dist --no-progress с отдельным COMPOSER_CACHE_DIR; при поддержке вашей версией добавьте сухой прогон вместо полной записи в vendor.
export COMPOSER_CACHE_DIR="$WORK_ROOT/.composer-cache" composer validate --no-check-publish --no-interaction composer install --no-dev --no-interaction --prefer-dist --no-progress
Node: npm ci --dry-run или npm ls --package-lock-only; монорепо — --prefix.
export NPM_CONFIG_CACHE="$WORK_ROOT/.npm-cache" npm ci --dry-run --prefix "$REPO_ROOT/apps/web"
Ответ Jenkins: объединить логи, обрезать длину, status по exit code.
Сводка сборки: HTTP и webhook назад, повторы при ошибке
Обратно: POST в Jenkins через buildByToken с параметрами downstream job или во внутренний корпоративный webhook уведомлений. Полезная нагрузка компактная: имя репозитория, ветка, укороченный SHA, длительность префлайта, итоговый статус и при необходимости ссылка на сохранённый лог на Mac.
Backoff 2/4/8 с с небольшим джиттером, не более трёх попыток для 5xx и сетевых обрывов; для 429 читайте Retry-After. Всегда задавайте в curl явные --connect-timeout и --max-time, чтобы воркер Jenkins не зависал на полуоткрытом TCP.
SUMMARY='{"status":"ok","ref":"main","sha_short":"abc1234","duration_ms":4200}'
for i in 1 2 3; do
code=$(curl -sS -o /tmp/r -w "%{http_code}" --connect-timeout 5 --max-time 25 \
-X POST -H "Authorization: Bearer ${JENKINS_CALLBACK_TOKEN}" \
-H "Content-Type: application/json" -d "$SUMMARY" "$CALLBACK_URL") || code=000
[[ "$code" =~ ^2 ]] && break
sleep $((2 ** i))
done
SLO: p95 префлайта < 3 мин; параллелизм ≤ ядра минус один; TTL клонов в WORK_ROOT.
Частые ошибки: краткий FAQ
401 на шлюзе
Bearer, plist или allowlist; обновите секреты, launchctl kickstart -k, проверьте curl с агента.
Composer тянет не тот registry
Корень клона, project composer.json, глобальный config.
npm ci vs локальный ноутбук
Выровнять версию npm/node с сервисом (nvm, pin).
Сводка не дошла
URL коллбэка, 403 прокси, идемпотентность и ретраи.
Постоянный OpenClaw-шлюз на удалённом Mac
Стабильный хост для webhook и префлайта: центр помощи, тарифы, аренда и главная — только открытые страницы сайта.