Files
orchestrator/docs/operations/SETUP_WEBHOOKS.md

170 lines
6.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Webhook Setup: Plane + Gitea → Orchestrator
## Архитектура
```
Gitea (push/PR/CI) ──→ Nginx proxy ──→ Orchestrator /webhook/gitea
Plane (work_item/comment) ──→ Nginx proxy ──→ Orchestrator /webhook/plane
```
External URL: `https://openclaw.mva154.duckdns.org/orchestrator/`
Internal URL: `http://127.0.0.1:8500/`
---
## Gitea Webhook (per-repo)
Gitea-webhook — **per-repo**: создаётся для КАЖДОГО подключаемого к оркестратору репозитория
(`<repo>` ниже). Для новых проектов его создаёт onboarding-CLI
(`scripts/onboard_project.py apply`) — полный процесс см. `docs/operations/ONBOARDING.md`;
команды ниже — для ручной проверки/пересоздания на любом репо.
- URL: `https://openclaw.mva154.duckdns.org/orchestrator/webhook/gitea`
- Events: `push`, `pull_request`, `status`
- Secret: значение `ORCH_GITEA_WEBHOOK_SECRET` в `.env` — **ОДИН глобальный секрет на все
репо** (приёмник валидирует только его; новый секрет на одном репо сломал бы HMAC остальных —
при ротации меняется на всех репо разом)
- Signature header: `X-Gitea-Signature` (HMAC-SHA256 hex digest)
### Проверка
```bash
GITEA_TOKEN=$(grep ORCH_GITEA_TOKEN /home/slin/repos/orchestrator/.env | cut -d= -f2)
curl -s "http://localhost:3000/api/v1/repos/<owner>/<repo>/hooks" \
-H "Authorization: token ${GITEA_TOKEN}" | python3 -m json.tool
```
### Пересоздание (если нужно)
```bash
# Секрет переиспользуй из .env (ORCH_GITEA_WEBHOOK_SECRET); генерируй новый ТОЛЬКО при
# первичной настройке/осознанной ротации (и обнови вебхуки ВСЕХ репо):
GITEA_WEBHOOK_SECRET=$(grep ORCH_GITEA_WEBHOOK_SECRET /home/slin/repos/orchestrator/.env | cut -d= -f2)
curl -X POST "http://localhost:3000/api/v1/repos/<owner>/<repo>/hooks" \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"type": "gitea",
"active": true,
"config": {
"url": "https://openclaw.mva154.duckdns.org/orchestrator/webhook/gitea",
"content_type": "json",
"secret": "'${GITEA_WEBHOOK_SECRET}'"
},
"events": ["push", "pull_request", "status"],
"branch_filter": "*"
}'
```
---
## Plane Webhook
**Создан напрямую в PostgreSQL** (Plane CE не экспортирует webhook API через внешний /api/v1/).
- URL: `https://openclaw.mva154.duckdns.org/orchestrator/webhook/plane`
- Events: `issue` (work_item.created), `issue_comment` (comment.created)
- Secret: значение `ORCH_PLANE_WEBHOOK_SECRET` в `.env`
- Signature header: `X-Plane-Signature` (HMAC-SHA256 hex digest)
### Проверка
```bash
docker exec -e PGPASSWORD=plane plane-app-plane-db-1 psql -U plane -d plane -c \
"SELECT id, url, is_active FROM webhooks;"
```
### Ручная настройка через UI (альтернатива)
1. Открыть `https://plane.mva154.duckdns.org`
2. Workspace Settings → Webhooks → Add Webhook
3. URL: `https://openclaw.mva154.duckdns.org/orchestrator/webhook/plane`
4. Secret: значение из `ORCH_PLANE_WEBHOOK_SECRET` в `.env`
5. Events: Issue, Issue Comment
6. Save
### Пересоздание через SQL
```bash
PLANE_WEBHOOK_SECRET=$(openssl rand -hex 20)
# Обновить в .env: ORCH_PLANE_WEBHOOK_SECRET=<new_secret>
WORKSPACE_ID=$(docker exec -e PGPASSWORD=plane plane-app-plane-db-1 psql -U plane -d plane -t -A -c \
"SELECT id FROM workspaces WHERE slug='ag_proj'")
WEBHOOK_ID=$(cat /proc/sys/kernel/random/uuid)
docker exec -e PGPASSWORD=plane plane-app-plane-db-1 psql -U plane -d plane -c "
INSERT INTO webhooks (id, created_at, updated_at, deleted_at, workspace_id, url, is_active, secret_key, project, issue, module, cycle, issue_comment, is_internal, version)
VALUES ('${WEBHOOK_ID}', NOW(), NOW(), NULL, '${WORKSPACE_ID}',
'https://openclaw.mva154.duckdns.org/orchestrator/webhook/plane',
true, '${PLANE_WEBHOOK_SECRET}', true, true, false, false, true, false, 'v1');
"
```
---
## HMAC Signature Verification
Оба handler'а проверяют подпись:
- Если secret пустой в `.env` — верификация пропускается (для dev/debug)
- Если secret задан — запрос без валидной подписи получает `401 Unauthorized`
### Формат подписи
| Source | Header | Algorithm | Format |
|--------|--------|-----------|--------|
| Gitea | `X-Gitea-Signature` | HMAC-SHA256 | hex digest (без префикса) |
| Plane | `X-Plane-Signature` | HMAC-SHA256 | hex digest |
### Тест подписи вручную
```bash
SECRET=$(grep ORCH_GITEA_WEBHOOK_SECRET /home/slin/repos/orchestrator/.env | cut -d= -f2)
BODY='{"ref":"refs/heads/test","repository":{"name":"enduro-trails"},"commits":[]}'
SIG=$(echo -n "${BODY}" | openssl dgst -sha256 -hmac "${SECRET}" | awk '{print $NF}')
curl -X POST http://localhost:8500/webhook/gitea \
-H "Content-Type: application/json" \
-H "X-Gitea-Event: push" \
-H "X-Gitea-Signature: ${SIG}" \
-d "${BODY}"
# Expected: {"status":"accepted"}
```
---
## Переменные окружения (.env)
| Переменная | Описание |
|-----------|----------|
| `ORCH_GITEA_WEBHOOK_SECRET` | HMAC secret для Gitea webhook |
| `ORCH_PLANE_WEBHOOK_SECRET` | HMAC secret для Plane webhook |
| `ORCH_GITEA_TOKEN` | API token для Gitea |
| `ORCH_PLANE_API_TOKEN` | API token для Plane |
---
## Troubleshooting
```bash
# Логи Orchestrator
docker logs orchestrator --tail 50 2>&1 | grep -i "webhook\|signature\|401"
# События в БД
docker exec orchestrator python3 -c "
import sqlite3
conn = sqlite3.connect('/app/data/orchestrator.db')
for r in conn.execute('SELECT id, source, event_type, timestamp FROM events ORDER BY id DESC LIMIT 10').fetchall():
print(r)
"
# Gitea webhook delivery history
# Gitea UI → Settings → Webhooks → click webhook → Recent Deliveries
```
---
*Создано: 2026-05-21 | Автор: Dev-агент*