Files
orchestrator/docs/work-items/ORCH-104/04-test-plan.yaml
claude-bot 94a3f399f2
All checks were successful
CI / test (push) Successful in 58s
analyst(ET): auto-commit from analyst run_id=638
2026-06-11 20:19:18 +03:00

198 lines
13 KiB
YAML
Raw 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.
work_item: ORCH-104
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-11
model_used: claude-opus-4-8
title: "Установочный скрипт Lite-тиража: интерактивный installer (setup_lite)"
framework: pytest
scope: >
Новый операторский CLI scripts/setup_lite.py (имя-кандидат) + обновление
docs/deployment/LITE_SETUP.md + анти-дрейф тесты. Вне покрытия: реальные
TTY/сеть/docker/пакетные менеджеры (всё мокается/инжектируется), установка
Plane/Gitea (вне объёма Lite), сквозной прогон на живом хосте (ручной smoke
по LITE_SETUP §11 силами оператора/deploy-staging).
notes: >
Принципы (паттерн tests/test_bootstrap_script.py): вся решающая логика — чистые
функции (вердикты предусловий, классификатор discovery, когерентность портов,
рендер env, builder аргументов onboarding, step-движок), тестируемые без
TTY/сети/docker; интерактив — через инжектируемый I/O (скриптованные ответы);
файловые сценарии — на tmp_path; структурная гигиена — ast/эвристики по файлу
скрипта. Полный существующий регресс tests/ обязан остаться зелёным; имя модуля
скрипта в тестах — фактическое (если архитектор финализирует иное имя).
tests:
# ---------- AC-1 / FR-1: точка входа, режимы, step-движок ----------
- id: TC-01
type: unit
description: "Парсер CLI: существует read-only режим диагностики (ноль мутаций) и установочный режим; набор режимов закрыт; контракт соответствует ADR (паттерн plan/apply/verify ORCH-103)"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-02
type: unit
description: "Step-движок check→ensure: шаг с уже истинным check пропускается (skip) без вызова ensure; повторный прогон по фикстуре 'всё выполнено' — каскад skip, ни одной повторной мутации"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-03
type: unit
description: "Resume: прогон останавливается на manual-step (exit 2); повторный запуск продолжает с первого незавершённого шага, выполненные не перевыполняются"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-2 / FR-2: скан предусловий и офер установки ----------
- id: TC-04
type: unit
description: "Вердикты предусловий: полный набор фактов хоста (docker/compose v2/git/python3/node/claude-code/креды/docker-группа/uid-gid/ssh/порты) → все OK, блокеров нет"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-05
type: unit
description: "Факт 'docker отсутствует' → вердикт MISSING с конкретной командой установки под детектированный пакетный менеджер; инжектированный отказ от согласия → шаг MANUAL, команда напечатана, мутация НЕ выполнена"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-06
type: unit
description: "Неопределимый пакетный менеджер → честный MANUAL с готовыми командами и ссылкой на § LITE_SETUP (не молчаливый пропуск, не падение); uname != Linux x86_64 → WARN 'вне контура Lite'"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-3 / FR-3: discovery Plane/Gitea ----------
- id: TC-07
type: unit
description: "Классификатор discovery: фикстура docker-перечня с ДВУМЯ Plane-инсталляциями (разные compose-проекты) → ровно 2 кандидата с проектом/образами/портами; выбор пользователя применяется; пункт 'ввести вручную' присутствует"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-08
type: unit
description: "Discovery: одна инсталляция → её URL префилл по умолчанию (с подтверждением); ноль инсталляций → ручной ввод + подсказка про Bundled; посторонние образы (не Plane/не Gitea) в кандидаты не попадают"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-09
type: unit
description: "Discovery best-effort: ошибка/недоступность docker при перечислении → ручной ввод URL без падения и без блокировки прогона (never-block)"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-4 / FR-4: интерактивный сбор + верификация + секрет-гигиена ----------
- id: TC-10
type: unit
description: "Цикл запроса с инжектированным I/O: верификация токена падает (401, мок) → re-prompt с диагнозом; после лимита попыток → MANUAL/остановка exit 2, НЕ бесконечный цикл; успешная верификация → значение принято"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-11
type: unit
description: "Секрет-гигиена: секретные значения запрашиваются скрытым вводом и отсутствуют в stdout-транскрипте и итоговом отчёте (печатаются только имена ключей)"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-12
type: unit
description: "non-TTY без неинтерактивной альтернативы → честный отказ с подсказкой (детерминированный exit), НЕ зависание на ожидании ввода"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-5 / FR-6: сборка .env / .env.watchdog ----------
- id: TC-13
type: integration
description: "Рендер на tmp_path: собранный .env содержит все группы обязательных ключей §4.2 LITE_SETUP; .env.watchdog содержит WATCHDOG_TG_BOT_TOKEN/WATCHDOG_TG_CHAT_ID (файл-носитель §4.3); webhook-секреты свежие 64-hex и различаются между прогонами"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-14
type: integration
description: "Существующий .env (и отдельно .env.watchdog) на tmp_path → отказ exit 2 без force-флага, файл байт-в-байт не изменён; с явным force — перезапись выполняется"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-15
type: unit
description: "Подсказки-дефолты промптов берутся из .env.example/автодетекта и не содержат боевых значений исходного хоста (ни секретов, ни хост-литералов: переиспользовать FORBIDDEN-набор test_no_host_hardcodes)"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-6 / FR-5: порты ----------
- id: TC-16
type: unit
description: "Когерентность портов: смена прод-порта → синхронно согласованы ORCH_DEPLOY_PROD_TARGET_PORT ⇄ WATCHDOG_METRICS_URL ⇄ ORCH_POST_DEPLOY_BASE_URL; занятый порт (мок busy-check) → предложена альтернатива"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-17
type: unit
description: "ORCH_STAGING_PORT == прод-порт → отказ fail-closed (значение не принято; инвариант ORCH-058/101)"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-7..AC-8 / FR-7: машинная охрана нормативов ----------
- id: TC-18
type: unit
description: "Telegram C-1: одинаковые токены бота орка и watchdog-бота → отказ шага с объяснением запрета; различные валидные (getMe ok, мок) → PASS шага"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-19
type: unit
description: "Gitea branch protection (мок API): непустой branch_protections на main → FAIL шага с лечением §6.4, БЕЗ попытки удаления правил скриптом; пустой список → PASS"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-20
type: unit
description: "Webhook Plane Path Б (SQL): выполняется только при явном согласии — инжектированный отказ → MANUAL-чекпоинт с инструкцией UI-пути, мутирующий вызов НЕ произведён (мок); после согласия — обязательная пост-верификация"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-9 / FR-8: запуск и health ----------
- id: TC-21
type: unit
description: "Шаг запуска (моки compose/HTTP): up только после согласия; состав 'ровно orchestrator + orchestrator-watchdog' → PASS, поднятый staging/третий сервис → FAIL шага; health требует /health 200 ok + /queue JSON + /metrics schema_version 1; чужие задачи в /queue → FAIL stateless-проверки"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-10 / FR-9: onboarding-кирпич ----------
- id: TC-22
type: unit
description: "Builder аргументов onboard_project.py — чистая функция от собранных ответов (имя/repo/prefix/stack/test-cmd/порты/webhook-url); последовательность plan→согласие→apply→verify; exit 2 кирпича транслируется как MANUAL; скрипт не несёт собственного канона статусов/лейблов"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-11 / FR-1, FR-10: exit-коды ----------
- id: TC-23
type: unit
description: "Контракт exit-кодов: все шаги PASS → 0; manual-step/незавершённое предусловие → 2; ошибка → 1; коды — именованные константы"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-12: структурная гигиена скрипта ----------
- id: TC-24
type: unit
description: "ast-скан: импорты скрипта — только python stdlib; модули платформы (src.*) не импортируются; канонические кирпичи gen_secrets.py/onboard_project.py и LITE_SETUP.md упомянуты"
module: tests/test_setup_lite_script.py
expected: PASS
- id: TC-25
type: unit
description: "Эвристический скан: delete-операций нет (rm -rf, compose down -v, DELETE-вызовы API, push --delete и т.п.); import модуля скрипта не имеет side effects (ничего не пишет/не запускает)"
module: tests/test_setup_lite_script.py
expected: PASS
# ---------- AC-13..AC-14: рантайм и документация ----------
- id: TC-26
type: integration
description: "Рантайм байт-в-байт: полный существующий регресс pytest tests/ -q зелёный; src/**, корневой docker-compose.yml, Dockerfile, .env.example, .env.watchdog.example задачей не изменены"
module: tests/ (полный регресс)
expected: PASS
- id: TC-27
type: unit
description: "LITE_SETUP.md вводит установочный скрипт как рекомендованный быстрый путь (упоминание файла скрипта в доке) и сохраняет ручной маршрут; все проверки test_lite_setup_doc.py зелёные (при изменении пиннингуемой структуры тест обновлён в том же PR)"
module: tests/test_lite_setup_doc.py
expected: PASS