Files
wiki/tasks/multi-agent/DEV_TASK_WEBHOOKS.md
2026-05-21 16:00:01 +03:00

10 KiB
Raw Blame History

DEV TASK: Настройка Webhooks (Plane + Gitea → Orchestrator)

Статус: Ready for dev
Проект: multi-agent
Фаза: 3
Предыдущая задача: DEV_TASK_ORCHESTRATOR_QG.md (выполнена)


Цель

Plane и Gitea автоматически отправляют webhook events в Orchestrator при действиях пользователя (создание задачи, комментарий, push, PR, CI status).

Архитектура

Nginx proxy уже настроен: https://openclaw.mva154.duckdns.org/orchestrator/localhost:8500.

Нужно:

  1. Создать webhook в Gitea через API (events: push, pull_request, status)
  2. Создать webhook в Plane через API или UI (events: work_item.created, comment.created)
  3. Добавить HMAC-верификацию подписи в обоих handlers
  4. Добавить webhook secret в .env Orchestrator'а
  5. Проверить end-to-end: действие в UI → webhook → Orchestrator обрабатывает

Стек / Зависимости

  • httpx (уже есть)
  • hmac + hashlib (stdlib)
  • Gitea API v1
  • Plane API v1

Инфраструктура

Параметр Значение
Сервер slin@82.22.50.71 (mva154)
Orchestrator URL (external) https://openclaw.mva154.duckdns.org/orchestrator/
Orchestrator URL (internal) http://127.0.0.1:8500/
Gitea API http://localhost:3000/api/v1
Gitea token в .env ORCH_GITEA_TOKEN
Plane API http://localhost:8091/api/v1
Plane token в .env ORCH_PLANE_API_TOKEN
Plane workspace ag_proj
Gitea repo owner admin
Gitea repo enduro-trails

Задачи

Task 1: Создать webhook в Gitea через API

Шаги:

  • 1.1 Создать webhook для репо admin/enduro-trails:
# Сгенерировать secret
GITEA_WEBHOOK_SECRET=$(openssl rand -hex 20)
echo "ORCH_GITEA_WEBHOOK_SECRET=${GITEA_WEBHOOK_SECRET}" >> /home/slin/repos/orchestrator/.env

# Создать webhook через API
curl -s -X POST "http://localhost:3000/api/v1/repos/admin/enduro-trails/hooks" \
  -H "Authorization: token $(grep ORCH_GITEA_TOKEN /home/slin/repos/orchestrator/.env | cut -d= -f2)" \
  -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": "*"
  }'
  • 1.2 Проверить что webhook создан:
curl -s "http://localhost:3000/api/v1/repos/admin/enduro-trails/hooks" \
  -H "Authorization: token $(grep ORCH_GITEA_TOKEN /home/slin/repos/orchestrator/.env | cut -d= -f2)" | python3 -m json.tool

Критерий готовности: Webhook виден в Gitea UI (Settings → Webhooks), URL правильный.


Task 2: Создать webhook в Plane

Шаги:

  • 2.1 Проверить Plane API для webhooks:
# Plane webhooks API
curl -s "http://localhost:8091/api/v1/workspaces/ag_proj/webhooks/" \
  -H "X-API-Key: $(grep ORCH_PLANE_API_TOKEN /home/slin/repos/orchestrator/.env | cut -d= -f2)" | python3 -m json.tool
  • 2.2 Создать webhook:
PLANE_WEBHOOK_SECRET=$(openssl rand -hex 20)
echo "ORCH_PLANE_WEBHOOK_SECRET=${PLANE_WEBHOOK_SECRET}" >> /home/slin/repos/orchestrator/.env

curl -s -X POST "http://localhost:8091/api/v1/workspaces/ag_proj/webhooks/" \
  -H "X-API-Key: $(grep ORCH_PLANE_API_TOKEN /home/slin/repos/orchestrator/.env | cut -d= -f2)" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://openclaw.mva154.duckdns.org/orchestrator/webhook/plane",
    "is_active": true,
    "secret_key": "'${PLANE_WEBHOOK_SECRET}'",
    "project": null
  }'

Примечание: Plane API для webhooks может отличаться от документации. Если API не работает — настроить через UI (plane.mva154.duckdns.org → Settings → Webhooks).

  • 2.3 Если API не поддерживает webhooks — задокументировать и оставить TODO для ручной настройки через UI.

Критерий готовности: Webhook создан (через API или UI), URL указывает на Orchestrator.


Task 3: HMAC-верификация подписи в webhook handlers

Файлы:

  • Изменить: src/webhooks/plane.py
  • Изменить: src/webhooks/gitea.py
  • Изменить: src/config.py

Шаги:

  • 3.1 Добавить верификацию в src/webhooks/gitea.py:
import hmac
import hashlib
from ..config import settings

def verify_gitea_signature(body: bytes, signature: str) -> bool:
    """Verify Gitea webhook HMAC-SHA256 signature."""
    if not settings.gitea_webhook_secret:
        return True  # Skip verification if no secret configured
    expected = hmac.new(
        settings.gitea_webhook_secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

@router.post("/gitea")
async def gitea_webhook(request: Request):
    body = await request.body()
    signature = request.headers.get("X-Gitea-Signature", "")
    
    if not verify_gitea_signature(body, signature):
        raise HTTPException(status_code=401, detail="Invalid signature")
    
    # ... rest of handler
  • 3.2 Добавить верификацию в src/webhooks/plane.py:
# Plane использует свой формат подписи — проверить документацию
# Обычно: X-Plane-Signature header с HMAC-SHA256
def verify_plane_signature(body: bytes, signature: str) -> bool:
    if not settings.plane_webhook_secret:
        return True
    expected = hmac.new(
        settings.plane_webhook_secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
  • 3.3 Добавить from fastapi import HTTPException в оба файла

Критерий готовности: Запрос без правильной подписи → 401. С правильной → 200.


Task 4: Пересобрать и протестировать

Шаги:

  • 4.1 Пересобрать Orchestrator:
cd /home/slin/repos/orchestrator && docker compose up -d --build
  • 4.2 Проверить health:
curl -s http://localhost:8500/health
  • 4.3 Тест Gitea webhook — сделать push в enduro-trails:
cd /home/slin/repos/enduro-trails
echo "# webhook test $(date)" >> .webhook-test
git add .webhook-test && git commit -m "test: webhook delivery check" && git push origin feature/ET-002-poi-toggle
  • 4.4 Проверить что Orchestrator получил event:
docker logs orchestrator --tail 10 2>&1 | grep -i "gitea\|push"
  • 4.5 Проверить в БД:
docker exec orchestrator python -c "
import sqlite3
conn = sqlite3.connect('/app/data/orchestrator.db')
rows = conn.execute('SELECT id, source, event_type, timestamp FROM events ORDER BY id DESC LIMIT 3').fetchall()
for r in rows: print(r)
"
  • 4.6 Удалить тестовый файл:
cd /home/slin/repos/enduro-trails
git rm .webhook-test && git commit -m "test: cleanup webhook test" && git push origin feature/ET-002-poi-toggle

Критерий готовности: Push в Gitea → event появляется в Orchestrator БД. Логи показывают обработку.


Task 5: Настроить Plane webhook через UI (если API не сработал)

Если Task 2 не удался через API:

  • 5.1 Документировать инструкцию для ручной настройки:
1. Открыть https://plane.mva154.duckdns.org
2. Settings → Webhooks → Add Webhook
3. URL: https://openclaw.mva154.duckdns.org/orchestrator/webhook/plane
4. Secret: <значение из ORCH_PLANE_WEBHOOK_SECRET в .env>
5. Events: All (или work_item.created, comment.created)
6. Save
  • 5.2 Сохранить инструкцию в /home/slin/repos/orchestrator/docs/SETUP_WEBHOOKS.md

Критерий готовности: Документация есть. Webhook либо настроен, либо есть чёткая инструкция.


Проверка (Acceptance)

# Проверка Команда / Действие Ожидаемый результат
1 Gitea webhook создан GET /api/v1/repos/admin/enduro-trails/hooks Webhook с URL orchestrator
2 Push → event в БД git push + check DB Новый event source=gitea
3 Signature verification curl без подписи → 401 401 Unauthorized
4 Signature verification curl с правильной подписью → 200 200 accepted
5 Plane webhook Создать issue в Plane → check DB Event source=plane

Ограничения и контекст

  • ⚠️ Plane API для webhooks может не поддерживать программное создание — тогда через UI
  • ⚠️ Gitea webhook secret формат: X-Gitea-Signature: sha256=<hex>
  • ⚠️ НЕ удалять существующие данные в БД
  • ⚠️ Если signature verification ломает существующие smoke tests — сделать skip если secret пустой
  • 🚫 НЕ менять Nginx конфиг (уже настроен)
  • 🚫 НЕ менять порт Orchestrator'а

Деплой-чеклист

  • Webhook secret сгенерирован и добавлен в .env
  • Gitea webhook создан через API
  • Plane webhook создан (API или UI)
  • HMAC verification добавлена в handlers
  • docker compose up -d --build успешен
  • Push в Gitea → event в Orchestrator
  • Логи чистые, нет ошибок

Создано: 2026-05-21 | Автор ТЗ: Стрим | Исполнитель: Dev-агент