151 lines
10 KiB
YAML
151 lines
10 KiB
YAML
work_item: ORCH-104
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-12
|
||
model_used: claude-opus-4-8
|
||
title: "Установочный скрипт для Lite — интерактивный установщик scripts/install_lite.py"
|
||
framework: pytest
|
||
scope: >
|
||
FR-1..FR-11 / AC-1..AC-12. Покрывается поведение установщика (чистые функции + step-движок
|
||
с инъекцией фейков HTTP/процессов) и анти-дрейф (stdlib-only, no-delete, reuse-bricks, doc-sync,
|
||
invariant snapshot). ВНЕ объёма тестов: реальная установка пакетов, реальный docker compose up,
|
||
реальные Plane/Gitea/Telegram (unit/integration детерминированы, без сети/docker/LLM — NFR-7).
|
||
notes: >
|
||
Зеркало паттернов tests/test_bootstrap_script.py и tests/test_lite_setup_doc.py: модуль грузится
|
||
через importlib; side-effects (subprocess/HTTP/getpass/input) инъектируются фейками; чистые
|
||
функции (parse_env/render_env/preflight_verdict/distro-команда/discovery/select) тестируются
|
||
изолированно. Полный регресс `pytest tests/ -q` обязан оставаться зелёным. Имена функций ниже —
|
||
ориентир по образцу bootstrap_bundle.py; финальные сигнатуры уточняет архитектор/разработчик.
|
||
|
||
tests:
|
||
# ---- FR-1 / AC-1: entry-point и режимы ----
|
||
- id: TC-01
|
||
type: integration
|
||
description: "plan-режим (дефолт) печатает план + preflight и НЕ делает мутаций (нет записи .env, нет compose up); exit 0 при чистых предусловиях, 2 при блокерах."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-02
|
||
type: unit
|
||
description: "build_plan() возвращает нормативный список шагов Lite в правильном порядке (preflight→deps→discovery→inputs→secrets→env→up→onboard→health)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-2 / AC-2: скан предусловий ----
|
||
- id: TC-03
|
||
type: unit
|
||
description: "preflight-вердикт: отсутствие docker/compose/node, занятый прод-порт, mismatch uid:gid владельца repos-dir → блокеры; полностью укомплектованный хост → блокеров нет."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-3 / AC-3 / D-1: управляемая установка зависимостей ----
|
||
- id: TC-04
|
||
type: unit
|
||
description: "distro→команда: apt-хост даёт apt-команду установки, dnf-хост — dnf-команду; неизвестный дистрибутив → деградация на текстовую инструкцию (без команды-мутации)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-05
|
||
type: integration
|
||
description: "remediation: при отказе оператора (ответ 'N') и при отсутствии TTY установщик НЕ выполняет установку, печатает инструкцию и возвращает exit 2 (никакой молчаливой root-мутации)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-4 / AC-4 / D-2: детект Plane/Gitea + выбор ----
|
||
- id: TC-06
|
||
type: unit
|
||
description: "discovery: по фейковым фактам docker ps/портов с 2 кандидатами Plane возвращается ранжированный список из 2; 0 кандидатов → пустой список (триггерит ручной фолбэк)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-07
|
||
type: unit
|
||
description: "select_candidate: валидный индекс выбирает кандидата; индекс вне диапазона/пустой ввод → режим ручного ввода URL (never-raise)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-08
|
||
type: unit
|
||
description: "detect never-raise: исключение в пробе docker/порта/URL деградирует в 'кандидатов нет' и не роняет установщик (NFR-3)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-5 / AC-5: живая верификация ввода ----
|
||
- id: TC-09
|
||
type: integration
|
||
description: "verify-before-write: фейк Plane/Gitea, отвечающий 401, отклоняет токен — значение НЕ пишется в .env; ответ 200 принимает и пишет. Telegram getMe ok:false → отклонение."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-6 / FR-7 / AC-6 / AC-7: секреты и env ----
|
||
- id: TC-10
|
||
type: unit
|
||
description: "parse_env round-trip: KEY=value строки → словарь, комментарии/пустые игнорируются."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-11
|
||
type: unit
|
||
description: "render_env: ключи-override обновляются в каноне, комментарии сохранены, неизвестные ключи дописываются управляемым блоком; идемпотентно (повторный рендер стабилен)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-12
|
||
type: integration
|
||
description: "секрет-гигиена: после прогона ни одно секрет-значение не встречается в собранном stdout/логе (маскирование); записанные .env/.env.watchdog имеют права 600."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-13
|
||
type: integration
|
||
description: "no-silent-overwrite: при уже заполненных секретах повторный apply без --force их не перетирает (значения стабильны); webhook-секреты выпускаются вызовом gen_secrets.py, а не собственным кодом."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-9 / AC-7: онбординг кирпичом ----
|
||
- id: TC-14
|
||
type: integration
|
||
description: "onboard reuse: установщик вызывает onboard_project.py apply+verify субпроцессом (фейк), парсит merged ORCH_PROJECTS_JSON из отчёта и пишет его в .env; ручные пункты отчёта пробрасываются (exit 2)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- FR-1 / FR-10 / AC-8 / AC-11: идемпотентность, health, no-TTY ----
|
||
- id: TC-15
|
||
type: integration
|
||
description: "идемпотентность: два apply подряд (фейки) → второй помечает шаги skipped, без дублей проекта/webhook, значения .env стабильны."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-16
|
||
type: integration
|
||
description: "no-TTY fail-closed: stdin не tty → manual_checkpoint печатает инструкцию и поднимает остановку → exit 2 (никакого зависания на input)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-17
|
||
type: integration
|
||
description: "health-гейт: фейк отвечает 200 на /health и валидным JSON на /queue,/metrics → сводка PASS, exit 0; /health не 200 → exit 1 с диагностикой (нет ложного success)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- AC-9 / AC-10 / INV: структурные анти-дрейф ----
|
||
- id: TC-18
|
||
type: unit
|
||
description: "stdlib-only + no-src-import: AST-скан install_lite.py — импорты только из разрешённого stdlib-набора; нет 'from src'/'import src' (зеркало test_bootstrap_script)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-19
|
||
type: unit
|
||
description: "no-delete-ops: AST/regex-скан не находит деструктивных операций (docker … rm/down -v, rm -rf, git push --force, удаление веток) и хост-хардкодов (FORBIDDEN-набор test_no_host_hardcodes)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-20
|
||
type: unit
|
||
description: "reuse-bricks / anti-fork: скрипт ссылается на gen_secrets.py и onboard_project.py; не несёт захардкоженного канона имён статусов Plane (FORBIDDEN_STATUS_NEEDLES) и собственной генерации секретов."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
- id: TC-21
|
||
type: unit
|
||
description: "invariant snapshot: STAGE_TRANSITIONS/QG_CHECKS не изменены этим PR (существующий снапшот-тест зелёный; ORCH-104 их не трогает)."
|
||
module: tests/test_install_lite_script.py
|
||
expected: PASS
|
||
|
||
# ---- AC-12: синхронизация документации ----
|
||
- id: TC-22
|
||
type: unit
|
||
description: "doc-sync: tests/test_lite_setup_doc.py ассертит, что LITE_SETUP.md ссылается на install_lite.py как рекомендованный путь; все существующие проверки дока (13 разделов, кирпичи, env key-sync, секрет-гигиена) остаются зелёными."
|
||
module: tests/test_lite_setup_doc.py
|
||
expected: PASS
|