110 lines
9.6 KiB
Markdown
110 lines
9.6 KiB
Markdown
---
|
||
work_item: ORCH-101
|
||
stage: architecture
|
||
author_agent: architect
|
||
status: proposed
|
||
created_at: 2026-06-10
|
||
model_used: claude-opus-4-8
|
||
---
|
||
|
||
# adr-0036: Фундамент тиража платформы — параметризация хоста, секреты, smoke (ORCH-101, 10-common)
|
||
|
||
## Статус
|
||
Proposed
|
||
|
||
## Контекст
|
||
|
||
Эпик ORCH-10 (D5.3 «Масштаб») — тираж платформы для заказчиков-тестеров двумя типами (A Lite /
|
||
B Bundled), оба stateless. Платформа была фактически прибита к хосту `mva154`: четыре места в
|
||
`src/**` обходили конфиг (внешний Gitea-URL в `plane_sync`, HOME + git-идентичности акторов в
|
||
`launcher`/`self_deploy`/`post_deploy`), `docker-compose.yml`/`Dockerfile`/deploy-hook несли
|
||
литералы путей/uid/gid/портов; механизма выпуска нового комплекта секретов и процедуры верификации
|
||
развёрнутой копии не существовало. ORCH-101 (10-common) — общий фундамент обоих типов тиража.
|
||
|
||
Это сквозное решение: оно задаёт **платформенные конвенции тиража** и трогает блоки, помеченные
|
||
маркерами ORCH-036/ORCH-040/ORCH-058 (по `docs/_standards/TRACEABILITY.md` — сводный ADR вместо
|
||
архео-перечисления). Детальный пакет решений (D1…D10) — work-item ADR:
|
||
`docs/work-items/ORCH-101/06-adr/ADR-001-host-parametrization-secrets-smoke.md`.
|
||
|
||
## Решение
|
||
|
||
**Принцип: «дефолт = боевое значение».** Каждое хост-специфичное значение читается из конфига
|
||
(`Settings` env `ORCH_*` / compose-интерполяция `${VAR:-default}` / Dockerfile `ARG` /
|
||
shell-default хука) с дефолтом, равным текущему боевому значению. Отсутствие новых переменных =
|
||
байт-в-байт текущее поведение (kill-switch-природа; отдельный функциональный флаг не вводится).
|
||
`src/config.py` и `watchdog/config.py` — единственные легитимные места хост-литералов в коде.
|
||
|
||
**Новые конфиг-ключи:** `agent_home_dir` (`ORCH_AGENT_HOME_DIR`, `/home/slin`) — HOME всех
|
||
акторских процессов; `agent_git_name` (`claude-bot`) + `git_email_domain` (`mva154.local`) —
|
||
git-идентичности (`<actor>@<domain>`; системные акторы `deploy-finalizer`/`post-deploy-monitor` —
|
||
платформенные литералы); `staging_port` (`ORCH_STAGING_PORT`, `8501`). Ссылки в Plane-комментариях —
|
||
из существующих `gitea_public_url`/`gitea_owner`. Compose-слой — карта `ORCH_HOST_*`/
|
||
`ORCH_DOCKER_GID`/`ORCH_RUN_UID/GID` + реюз `ORCH_DEPLOY_*`; порт прод/стейджинг — явные `command:`
|
||
с `${ORCH_DEPLOY_PROD_TARGET_PORT:-8500}` / `${ORCH_STAGING_PORT:-8501}` (CMD образа не трогается —
|
||
exec-form + `init: true` сохранены).
|
||
|
||
**Платформенные конвенции тиража (нормативно):**
|
||
1. **`SELF_HOSTING_REPO = "orchestrator"` — константа, не конфиг.** На ней «empty CSV →
|
||
self-hosting only» всех `*_repos`-leaf'ов; конфигурируемость превращала бы опечатку env в
|
||
активацию деплой-машинерии на чужом репо или тихое выключение всех self-гейтов. Репо платформы
|
||
в тираже обязан называться `orchestrator` (REPLICATION.md).
|
||
2. **Имена compose-сервисов/контейнеров/образов, профиль `staging`, `network_mode: host`,
|
||
контейнерный layout (`/app/data`, `/repos`, `/opt/claude-code`)** — конвенции, не переменные
|
||
(для образов истина уже в конфиге `deploy_prod_*_image`).
|
||
3. **Staging-порт конфигурируем ТОЛЬКО с fail-closed guard'ом** (усиление инварианта ORCH-058
|
||
AC-9): freshness-путь отказывает ДО любого ssh/build при
|
||
`staging_port == deploy_prod_target_port` — без тихого fallback. Explicit-pass таргета хуку
|
||
(`TARGET_PORT=` и др.) сохранён; добавлена явная передача `REPO=` обоими инвокерами хука
|
||
(его строка 38 становится `"${REPO:-…}"` — exit-контракт 0/1/2 ORCH-036 не тронут).
|
||
4. **Группа ORCH-040 неделима:** uid/gid/HOME/маунт-таргеты/`useradd` управляются одними env
|
||
насквозь (`ORCH_RUN_UID/GID`, `ORCH_AGENT_HOME_DIR` → compose `user:`/таргеты/`build.args
|
||
APP_*`); `group_add` docker-gid («МИНА 1») не удаляется — литерал станет
|
||
`${ORCH_DOCKER_GID:-999}`.
|
||
|
||
**Секреты нового хоста:** stdlib-скрипт `scripts/gen_secrets.py` — криптослучайные webhook-секреты
|
||
(`secrets.token_hex(32)`), печать по умолчанию, `--write` отказывает при существующем `.env`
|
||
(перезапись — только явный `--force`); внешние токены (Plane/Gitea/Telegram/watchdog) — по
|
||
чек-листу. Норматив: **боевые секреты текущего хоста не копируются ни на одном шаге**.
|
||
|
||
**Smoke-верификация тиража:** runbook `docs/operations/REPLICATION.md` (deployment golden source:
|
||
карта env, чек-лист секретов, пошаговый smoke с PASS/FAIL: `compose config` → `/health` →
|
||
`/queue`+`/metrics` → `onboard_project.py plan/apply/verify` → тестовая задача → артефакты `01–04`
|
||
в ветке; расширенно — до `done`; границы 10-common vs Lite vs Bundled). Нового smoke-скрипта нет —
|
||
шаги собраны из существующих кирпичей.
|
||
|
||
**Анти-регресс (постоянная CI-гарантия):** структурный сканер `tests/test_no_host_hardcodes.py` —
|
||
запрещённые литералы (`82.22.50.71`, `/home/slin`, `mva154`, `duckdns`; список централизован) в
|
||
исполняемом коде `src/**`+`watchdog/**`; `tokenize`-исключение комментариев/докстрингов;
|
||
структурное исключение двух config-модулей (канон дефолтов); allowlist пуст; негативная
|
||
самопроверка.
|
||
|
||
### Что НЕ меняется
|
||
`STAGE_TRANSITIONS`, состав `QG_CHECKS`, семантика `check_*`, machine-verdict ключи, схема БД —
|
||
байт-в-байт; значения существующих конфиг-дефолтов; INV-4; прод-контейнер в рамках задачи не
|
||
рестартуется (правки compose/Dockerfile инертны до штатного деплоя через staging 8501 →
|
||
`Confirm Deploy`).
|
||
|
||
## Альтернативы
|
||
- **`ORCH_SELF_HOSTING_REPO` конфигом** — отвергнуто: узел безопасности; опечатка = групповой риск.
|
||
- **Staging-порт константой** — отвергнуто: compose-порт параметризуется (AC-6), константа дала бы
|
||
рассинхрон слоёв; пара «ключ + guard» строго сильнее.
|
||
- **Smoke-скрипт-обвязка / генератор в `onboard_project.py`** — отвергнуто: лишняя поверхность;
|
||
разные жизненные циклы (онбординг проекта ≠ provisioning хоста).
|
||
|
||
## Последствия
|
||
- Платформа разворачивается на чужой инфре env-конфигурацией; критический путь ORCH-10 разблокирован
|
||
(Lite/Bundled строятся поверх REPLICATION.md).
|
||
- Инвариант ORCH-058 переходит из «подразумеваемого константой» в исполняемый guard; возврат
|
||
хост-хардкода ломает CI структурно.
|
||
- Цена: ~13 новых env-имён (на текущем хосте настраивать нечего — дефолты боевые) и правило
|
||
«интерполяция читает `.env`/shell, не `env_file`» (зафиксировано в REPLICATION.md).
|
||
- Откат: не задавать переменные (дефолты = прежнее поведение); полный — revert PR (без миграций).
|
||
|
||
## Связи
|
||
adr-0005 (ORCH-040 — uid/HOME/«МИНА 1»; группа становится параметризуемой, инвариант сохранён),
|
||
adr-0008 (ORCH-058 — INV-FRESH/AC-9; guard усиливает), adr-0007 (ORCH-036 — exit-контракт хука
|
||
не тронут), adr-0035 (ORCH-009 — onboarding переиспользуется smoke-процедурой; kit не форкается),
|
||
adr-0001 (`is_self_hosting_repo` — конвенция имени закреплена). Детально —
|
||
`docs/work-items/ORCH-101/06-adr/ADR-001-host-parametrization-secrets-smoke.md` (D1…D10),
|
||
`07-infra-requirements.md`, `10-tech-risks.md`.
|