diff --git a/tasks/orchestrator/DEV_TASK_ORCH33_STAGING_TESTSUITE.md b/tasks/orchestrator/DEV_TASK_ORCH33_STAGING_TESTSUITE.md new file mode 100644 index 0000000..84fe1b7 --- /dev/null +++ b/tasks/orchestrator/DEV_TASK_ORCH33_STAGING_TESTSUITE.md @@ -0,0 +1,65 @@ +# DEV TASK — ORCH-33: тест-сьют для staging-стенда (smoke + доступы + e2e) + +**Проект:** orchestrator | **Сервер:** slin@82.22.50.71 (pw motoZ@yaz2010) | **Репо:** /home/slin/repos/orchestrator | **Контейнеры:** orchestrator (прод 8500), orchestrator-staging (8501) +**Ветка:** создать `feature/ORCH-33-staging-testsuite` из свежего origin/main. `git fetch origin && git checkout main && git pull --ff-only && git checkout -b feature/ORCH-33-staging-testsuite`. +**Этап:** 3 из 5 (после Этапов 1-2: staging-контейнер ПОДНЯТ и живой на 8501, песочница готова). + +## ЦЕЛЬ +Написать **самостоятельный скрипт-сьют** `scripts/staging_check.py` (+ docs), который проверяет, что живой staging-стенд реально работоспособен. НЕ unit-тесты (они уже есть в tests/), а **проверка живого стенда** через HTTP/API. Запускается вручную/из деплой-хука против работающего staging на 8501. + +## ОКРУЖЕНИЕ (факты, проверены на проде 05.06) +- **staging:** http://localhost:8501 — `/health` -> `{"status":"ok","service":"orchestrator"}`, `/queue` -> JSON со счётчиками. Контейнер `orchestrator-staging`, образ `orchestrator-orchestrator-staging:latest`. +- **Песочница Plane:** проект "ORCH Sandbox", identifier `SANDBOX`, **project_id `8c5a3025-4f9d-4190-b79f-fa06276bb27e`**. +- **Песочница Gitea:** репо `admin/orchestrator-sandbox` (main, auto-init). +- **Реестр staging:** `ORCH_PROJECTS_JSON` содержит ТОЛЬКО sandbox → `known_plane_project_ids()` = {8c5a3025...}. Боевые ET/ORCH staging НЕ видит (фильтр ORCH-6 режет в ignored). +- **Токены (внутри контейнера orchestrator-staging, через env):** `ORCH_PLANE_API_TOKEN`, `ORCH_PLANE_WORKSPACE_SLUG` (=ag_proj), `ORCH_PLANE_API_URL` (=http://localhost:8091, код добавляет /api/v1), `ORCH_GITEA_TOKEN`, `ORCH_GITEA_URL` (=http://localhost:3000). Plane-заголовок `X-API-Key`, Gitea-заголовок `Authorization: token `. +- ⚠️ Plane API URL БЕЗ /api/v1 в env — суффикс добавляет КОД. Если дёргаешь Plane напрямую — добавь /api/v1 сам, иначе Plane вернёт HTML(200) вместо JSON. + +## ЧТО ДОЛЖЕН ДЕЛАТЬ `scripts/staging_check.py` +Скрипт принимает базовый URL staging (дефолт http://localhost:8501) и режим. Запускается ВНУТРИ контейнера orchestrator-staging (там есть токены и сетевой доступ к localhost:8091/3000) ИЛИ умеет читать токены из env. Структура — три блока, каждый печатает PASS/FAIL и в конце общий итог + exit code (0 = всё PASS, !=0 = есть FAIL): + +### Блок A — SMOKE (быстрый, без побочных эффектов) +1. `GET /health` -> 200 и `status==ok`. +2. `GET /queue` -> 200, есть ключи counts/max_concurrency/resilience. +3. Проверка, что это ИМЕННО staging: `ORCH_STAGING==true` в env контейнера (или эндпоинт, если есть). Если падает прод-URL по ошибке — НЕ продолжать деструктив. + +### Блок B — ДОСТУПЫ (реальные вызовы в песочницу, read-only) +4. Plane: `GET {PLANE}/api/v1/workspaces/{slug}/projects/` своим токеном -> 200, среди проектов есть id `8c5a3025-...` (sandbox доступен). +5. Gitea: `GET {GITEA}/api/v1/repos/admin/orchestrator-sandbox` своим токеном -> 200 (sandbox-репо доступен на запись — проверить `permissions.push==true`). +6. Реестр: внутри контейнера `from src.projects import known_plane_project_ids` -> содержит sandbox и НЕ содержит боевые ET(7a79f0a9)/ORCH(8da6aa25). (Гарантия изоляции.) + +### Блок C — E2E (реальный прогон в песочнице, побочные эффекты ТОЛЬКО в sandbox) +⚠️ **ВАЖНО — разведано на проде 05.06, РЕЖИМА ЗАГЛУШЕК АГЕНТОВ В КОДЕ НЕТ** (гибрид C из дизайна ещё не реализован). НО он и НЕ НУЖЕН для e2e. Порядок `start_pipeline` (разведан по коду): resolve проекта → подтяг name/desc из Plane API → **QG-0** валидация (жёсткий гейт!) → **создание work_item_id + ветки + начальных доков + строки задачи** → ПОТОМ enqueue аналитика (вот тут Claude CLI). +**Ключ e2e:** ветка+доки+коммент QG-0 создаются ДО запуска LLM. Проверяем ИМЕННО эти ранние артефакты, АНАЛИТИКА НЕ ЖДЁМ и НЕ ВЫЗЫВАЕМ (он встанет в очередь — это ок, не проблема). Так e2e быстрый и детерминированный, без расхода LLM-кредитов. + +Шаги: +7. Создать тестовую задачу в Plane-проекте SANDBOX через API. ⚠️ QG-0 жёсткий: name ≥ 3 символов И description ≥ 20 символов — иначе конвейер упрётся в QG-0 fail и ветку НЕ создаст. Дай задаче НОРМАЛЬНЫЙ заголовок (`[staging-check] e2e `) И description ≥ 20 символов. +8. Триггер конвейера = переход В In Progress. Webhook Plane→staging НЕ настроен → самый детерминированный путь: **прямой POST на staging `http://localhost:8501/webhook/plane`** с корректным payload (issue updated, new state = In Progress, project=8c5a3025...) + подпись HMAC (см. ниже). Структуру payload и имя state-поля сверь с `src/webhooks/plane.py` (handle_status_start, PLANE_STATES) и с эталонным тестом `tests/test_webhooks.py::test_plane_webhook_creates_task`. +9. Поллить с таймаутом (~30-60с) и проверить по факту через API: + - в Gitea `orchestrator-sandbox` появилась ветка под задачу (GET .../branches); + - в Plane-задаче появился коммент от орка (GET issue comments) — напр. QG-0 или «ветка создана»; + - (опц.) строка задачи появилась в staging-БД (можно через `/queue` или SQL в data/staging/orchestrator.db). +10. **CLEANUP (try/finally, ВСЕГДА):** удалить созданную ветку в sandbox-репо + закрыть/удалить тест-задачу в SANDBOX, чтобы песочница не засорялась. Отработать даже если e2e упал. + +**режимы:** поддержи `--mode stub|full-real` ради будущего, НО понимай: сейчас стуб-режима агентов НЕТ, поэтому stub-прогон просто НЕ ЖДЁТ аналитика (проверяет ранние артефакты: ветка/доки/коммент). full-real — дополнительно дожидается реального Claude CLI (длинный, расход кредитов), НЕ дефолт. Если stub-режим требует реального изменения src (чтобы не дёргался LLM) — СТОП, отчёт (src править нельзя, это отдельная задача). + +## HMAC-секрет для блока C (если webhook на staging требует подпись) +- staging `.env.staging` копирует `ORCH_PLANE_WEBHOOK_SECRET` из прода. Если он непустой — твой запрос на `/webhook/plane` должен нести валидную подпись. Прочитай реальный секрет из env контейнера staging и сформируй подпись тем же алгоритмом, что использует код (`src/webhooks/plane.py` — посмотри как проверяет). НЕ хардкодь секрет в скрипт — читай из env в рантайме. +- Если проще и надёжнее — создавай задачу и меняй статус ЧЕРЕЗ Plane API (тогда настоящий Plane сам пошлёт webhook... но только если webhook в Plane настроен на 8501 — а он пока НЕ настроен). Поэтому самый детерминированный путь для блока C: **прямой POST на staging `/webhook/plane`** с корректным payload + подпись. Документируй выбранный путь. + +## ⛔ OFF-LIMITS / ПРАВИЛА +- НЕ трогать src/ (логику орка), tests/ (unit), docker-compose.yml, .env, .env.staging. Только НОВЫЕ файлы: `scripts/staging_check.py` + `docs/STAGING_CHECK.md` (как запускать). Если для работы нужен крошечный helper — клади в scripts/. +- E2E пишет ТОЛЬКО в песочницу (SANDBOX-проект + orchestrator-sandbox-репо). НИКОГДА в боевые ET/ORCH/enduro-trails/orchestrator. Если код может задеть боевое — СТОП, отчёт. +- НЕ дёргать прод (8500). Все вызовы — на 8501 и в sandbox-сущности. +- НЕ регистрировать раннеров, НЕ nohup. Раннер mva154-runner-orch уже есть. +- PR push в main ЗАПРЕЩЁН. НЕ мержить — только коммит в ветку + PR. +- Если факт разошёлся с ТЗ (эндпоинт другой, нет нужного API, конвейер в stub не доходит до ветки) — СТОП, отчёт с вопросом, НЕ угадывать и не продавливать. + +## ПРОВЕРКА (обязательный пруф в отчёт) +1. Запустить сьют против ЖИВОГО staging: `docker exec orchestrator-staging python3 /repos/orchestrator/scripts/staging_check.py --mode stub` (или как удобнее запускать — задокументируй). Приложи ВЕСЬ вывод: блок A/B/C, PASS/FAIL по каждому пункту, итог, exit code. +2. Доказать, что после прогона песочница почищена (ветка удалена) и БОЕВЫЕ проекты/репо НЕ затронуты (нет новых веток в orchestrator/enduro-trails, нет задач в боевом ORCH). +3. Прод 8500 `/health` = ok (не пострадал). +4. `git log --oneline origin/main..origin/feature/ORCH-33-staging-testsuite` — коммит ВИДЕН (после push, до отчёта «PR готов»). + +## РЕЗУЛЬТАТ +Новые файлы: `scripts/staging_check.py` (smoke+доступы+e2e, exit-code, cleanup в finally, --mode stub|full-real) + `docs/STAGING_CHECK.md`. Прогон против живого staging зелёный (или честный отчёт где затык). PR в Gitea. Отчёт → `tasks/orchestrator/reports/dev-2026-06-05-orch33-staging-testsuite.md`. Коммит: `feat(staging): add live staging check suite (smoke + access + e2e)`.