198 lines
13 KiB
YAML
198 lines
13 KiB
YAML
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
|