From 732a19e5649be3a25dfa886bc988b5d586825566 Mon Sep 17 00:00:00 2001 From: Stream Date: Thu, 21 May 2026 16:00:01 +0300 Subject: [PATCH] auto-sync: 2026-05-21 16:00:01 --- tasks/multi-agent/DEV_TASK_WEBHOOKS.md | 284 +++++++++++++++++++++++++ tasks/multi-agent/STATUS.md | 33 +-- 2 files changed, 302 insertions(+), 15 deletions(-) create mode 100644 tasks/multi-agent/DEV_TASK_WEBHOOKS.md diff --git a/tasks/multi-agent/DEV_TASK_WEBHOOKS.md b/tasks/multi-agent/DEV_TASK_WEBHOOKS.md new file mode 100644 index 0000000..4e2d145 --- /dev/null +++ b/tasks/multi-agent/DEV_TASK_WEBHOOKS.md @@ -0,0 +1,284 @@ +# 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`: +```bash +# Сгенерировать 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 создан: +```bash +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: +```bash +# 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: +```bash +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`: +```python +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`: +```python +# 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: +```bash +cd /home/slin/repos/orchestrator && docker compose up -d --build +``` + +- [ ] **4.2** Проверить health: +```bash +curl -s http://localhost:8500/health +``` + +- [ ] **4.3** Тест Gitea webhook — сделать push в enduro-trails: +```bash +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: +```bash +docker logs orchestrator --tail 10 2>&1 | grep -i "gitea\|push" +``` + +- [ ] **4.5** Проверить в БД: +```bash +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** Удалить тестовый файл: +```bash +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=` +- ⚠️ НЕ удалять существующие данные в БД +- ⚠️ Если 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-агент* diff --git a/tasks/multi-agent/STATUS.md b/tasks/multi-agent/STATUS.md index 458cf7c..519151d 100644 --- a/tasks/multi-agent/STATUS.md +++ b/tasks/multi-agent/STATUS.md @@ -11,8 +11,8 @@ |----------------|--------|-------------| | **Фаза 0: Инфраструктура** | ✅ Завершена | Всё установлено и работает | | **Фаза 1: Ручной конвейер** | ✅ Завершена | ET-001 прошёл полный цикл | -| **Фаза 2: Orchestrator MVP** | 🟡 Частично | Каркас задеплоен, QG — заглушки, автозапуск не работает | -| **Фаза 3: Plane интеграция** | 🟡 Начата | Webhook receiver есть, логика обработки — заглушки | +| **Фаза 2: Orchestrator MVP** | ✅ Завершена (21.05) | QG реальные, автозапуск Claude CLI работает, 27 тестов green | +| **Фаза 3: Plane интеграция** | 🟡 В работе (21.05) | Webhook handlers готовы, настройка webhooks в Plane/Gitea UI — в процессе | | **Фаза 4: Полный конвейер** | ❌ Не начата | — | | **Фаза 5: Оптимизация** | ❌ Не начата | — | @@ -90,22 +90,25 @@ - ✅ SQLite БД инициализирована (tables: events, tasks, agent_runs) - ✅ AgentLauncher — класс написан, конфиги 5 агентов определены -### Что НЕ работает (заглушки) +### Что реализовано (21.05.2026 — DEV_TASK_ORCHESTRATOR_QG) -- ❌ `qg/checks.py` — все 4 функции возвращают хардкод (True/False), реальных проверок нет -- ❌ `handle_work_item_created` — создаёт запись в tasks, но НЕ создаёт ветку и НЕ запускает агента -- ❌ `handle_comment` — `:approved:` детектится, но НЕ определяет задачу и НЕ двигает stage -- ❌ `handle_push` / `handle_pr` / `handle_ci_status` — пустые `pass` -- ❌ AgentLauncher — ни разу не запускался автоматически (agent_runs: 0) -- ❌ Nginx proxy_pass на `/orchestrator/` — не найден (только localhost:8500) -- ❌ Plane webhooks → Orchestrator — не настроены в Plane UI -- ❌ Gitea webhooks → Orchestrator — не настроены в Gitea UI +- ✅ `qg/checks.py` — 5 реальных QG-проверок (filesystem + Gitea API) +- ✅ `handle_work_item_created` — создаёт task + ветку в Gitea + папку docs +- ✅ `handle_comment` — `:approved:` → QG check → advance stage → launch agent +- ✅ `handle_push` / `handle_pr` / `handle_ci_status` — полная обработка +- ✅ AgentLauncher — Claude CLI запускается из контейнера (binary mount) +- ✅ Stage machine (`src/stages.py`) — конечный автомат 8 стадий +- ✅ Notifications (`src/notifications.py`) — structured logging +- ✅ 27 тестов — all green +- ✅ Nginx proxy_pass `/orchestrator/` → localhost:8500 (уже был настроен) +- 🟡 Plane webhooks → Orchestrator — настройка в процессе +- 🟡 Gitea webhooks → Orchestrator — настройка в процессе -### Данные в БД +### Данные в БД (на 21.05.2026) -- events: 4 (тестовые, от 19.05.2026 — 2 plane + 2 gitea) -- tasks: 2 (тестовые) -- agent_runs: 0 +- events: 15 (4 старых + 11 от smoke tests) +- tasks: 6 (2 старых + 4 smoke tests: ET-001..ET-004) +- agent_runs: 3 (2x architect, 1x developer — реальные запуски Claude CLI) ---