analyst(ET): auto-commit from analyst run_id=174
All checks were successful
CI / test (push) Successful in 14s
All checks were successful
CI / test (push) Successful in 14s
This commit is contained in:
93
docs/work-items/ORCH-040/01-brd.md
Normal file
93
docs/work-items/ORCH-040/01-brd.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 01 — BRD: Агенты пишут файлы под root в смонтированный хост-репо
|
||||
|
||||
Work Item: **ORCH-040**
|
||||
Тип: инфра-фикс (runtime / docker-compose)
|
||||
Исполнение: через Dev напрямую (по решению Owner)
|
||||
|
||||
## 1. Бизнес-контекст и проблема
|
||||
|
||||
Контейнер `orchestrator` (prod, 8500) работает под `uid=0 (root)`. Он монтирует
|
||||
хостовый каталог `/home/slin/repos` → `/repos` (rw). Claude-CLI агенты запускаются
|
||||
через `subprocess.Popen` **внутри контейнера**, то есть тоже под root. Они пишут:
|
||||
|
||||
- в git worktree задач — `/repos/_wt/<repo>/<branch>/...`;
|
||||
- в прод-клон — `/repos/<repo>/docs/work-items/...` (через коммит/пуш из worktree).
|
||||
|
||||
В результате на **хосте** файлы создаются с владельцем `root:root`.
|
||||
|
||||
### Симптом
|
||||
При ребилде/деплое прода `git pull` / `git reset` под пользователем `slin` падает:
|
||||
|
||||
```
|
||||
error: insufficient permission for adding an object to repository database .git/objects
|
||||
Permission denied (на docs/work-items/ORCH-016, владелец root:root)
|
||||
```
|
||||
|
||||
Каждый будущий деплой будет ломаться, пока вручную не выполнить `chown`.
|
||||
|
||||
### Диагноз (живая разведка 05–06.06)
|
||||
- `docker exec orchestrator id` → `uid=0(root) gid=0(root) groups=0,999`.
|
||||
- Хост `slin` = `uid=1000 gid=1000`, группы: `sudo`, `docker(999)`.
|
||||
- `/home/slin/repos` → `/repos` (rw); на хосте `/repos` уже `1000:1000 rwxrwxr-x`.
|
||||
- `docs/work-items/*` на хосте — `root:root` (наследие прошлых прогонов).
|
||||
|
||||
## 2. Цель
|
||||
|
||||
Агенты конвейера **не должны** создавать `root`-файлы в хостовом репозитории.
|
||||
После любого прогона конвейера `git pull/status/reset` под `slin` на хосте
|
||||
работает **без ручного chown**.
|
||||
|
||||
## 3. Объём (scope)
|
||||
|
||||
В объёме:
|
||||
- Изменение runtime-режима контейнера так, чтобы артефакты создавались под
|
||||
`uid:gid` хоста (`1000:1000`).
|
||||
- Сохранение работоспособности: claude-auth (preflight), git/ssh, docker.sock
|
||||
(деплой), запуск конвейера.
|
||||
- Обновление документации (INFRA.md, CHANGELOG, ADR с обоснованием варианта).
|
||||
- Проверка на staging (8501) ДО прода.
|
||||
|
||||
Вне объёма:
|
||||
- Массовое исправление прав уже существующих `root:root` файлов в истории
|
||||
(разовый `chown` на хосте делает Owner; в задаче — только описать команду).
|
||||
- Изменение логики конвейера, QG, схемы БД.
|
||||
- Смена модели/effort агентов, прочие фичи.
|
||||
|
||||
## 4. Заинтересованные стороны
|
||||
- Owner (Слава) — заказчик, владелец хоста mva154.
|
||||
- Стрим — разведка/контекст.
|
||||
- Проект enduro-trails — co-tenant того же прод-инстанса (групповой риск).
|
||||
|
||||
## 5. Ограничения и риски (off-limits)
|
||||
|
||||
Self-hosting: прод-инстанс `orchestrator` ОДИН на все прод-проекты, общая БД и
|
||||
очередь. **Нельзя ломать**: запуск конвейера, доступ к Plane/Gitea/SSH из агентов,
|
||||
docker.sock. Любой рестарт контейнера под новым uid — **только в окно тишины**
|
||||
(нет активных задач). Тестировать на staging ПЕРЕД продом.
|
||||
|
||||
### Известные мины (подтверждены разведкой)
|
||||
- **МИНА 1 — docker.sock**: `/var/run/docker.sock` = `srw-rw---- root:999`.
|
||||
Доступ идёт через gid 999, не через root. При переходе на непривилегированный
|
||||
uid обязателен supplementary group `999`. *В текущем `docker-compose.yml` уже
|
||||
есть `group_add: ["999"]` для обоих сервисов — учесть, не сломать.*
|
||||
- **МИНА 2 — claude creds (БЛОКЕР)**: `/home/slin/.claude/.credentials.json` =
|
||||
`root:root 0600`. Сейчас читает контейнер-root. Под `uid=1000` без доступа →
|
||||
`claude-auth` ломается → весь конвейер умирает (preflight ORCH-044 заворачивает).
|
||||
Проверить ПЕРВЫМ.
|
||||
- **МИНА 3 — claude бинарь**: реальный бинарь `/opt/claude-code/bin/claude.exe`
|
||||
(root:root, `+x` для всех — ok). `ORCH_CLAUDE_BIN=/usr/bin/claude` в env не
|
||||
существует; launcher использует hardcode `CLAUDE_BIN=/opt/claude-code/bin/claude.exe`.
|
||||
Под uid 1000 исполним, но проверить запуск.
|
||||
- **SSH-маунт**: `/home/slin/.orchestrator-ssh` → `/root/.ssh:ro`. При смене uid
|
||||
HOME/домашний каталог меняется — путь к ключам нужно поправить (деплой по ssh).
|
||||
- **HOME**: launcher форсит `HOME=/home/slin` (две точки: env Popen и git_env).
|
||||
Креды читаются из `/home/slin/.claude`. Учесть при смене uid.
|
||||
|
||||
## 6. Бизнес-ценность
|
||||
Устранение постоянного ручного `chown` после каждого деплоя; деплой прода
|
||||
перестаёт ломаться на правах; снимается источник простоя конвейера всех проектов.
|
||||
|
||||
## 7. Допущения
|
||||
- Хост-каталоги `/app/data` и `/repos` уже `1000:1000` (запись под uid 1000 пройдёт).
|
||||
- Dockerfile уже содержит `git config --system --add safe.directory '*'`.
|
||||
- Окно тишины для рестарта контейнера согласуется с Owner.
|
||||
86
docs/work-items/ORCH-040/02-trz.md
Normal file
86
docs/work-items/ORCH-040/02-trz.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# 02 — ТЗ: agent-файлы под uid хоста (не root)
|
||||
|
||||
Work Item: **ORCH-040**
|
||||
|
||||
## 1. Суть требования
|
||||
Артефакты конвейера (worktree + docs) должны создаваться на хосте под
|
||||
`uid:gid = 1000:1000` (slin), а не `root:root`. При этом сохраняется работа
|
||||
claude-auth, git, ssh-деплоя и docker.sock.
|
||||
|
||||
## 2. Задействованные модули и файлы
|
||||
|
||||
| Файл | Роль в задаче |
|
||||
|------|----------------|
|
||||
| `docker-compose.yml` | runtime-режим контейнера (prod `orchestrator` + `orchestrator-staging`). Основная точка изменения. |
|
||||
| `Dockerfile` | возможные правки под непривилегированный запуск (safe.directory уже есть; при необходимости — создание пользователя/прав). |
|
||||
| `src/agents/launcher.py` | `HOME=/home/slin` хардкод (env Popen ~стр.326 и git_env ~стр.513); путь `CLAUDE_BIN` (стр.187). Проверить совместимость при смене uid; править ТОЛЬКО при необходимости. |
|
||||
| `docs/operations/INFRA.md` | блок «Тома (volumes)» (SSH-маунт `/root/.ssh`), карта рантайма — обновить. |
|
||||
| `CHANGELOG.md` | запись об изменении. |
|
||||
| `docs/work-items/ORCH-040/06-adr/` | ADR с выбором варианта + обоснованием (создаёт архитектор). |
|
||||
|
||||
## 3. Варианты решения (вход для ADR — выбор и обоснование за архитектором)
|
||||
|
||||
> Анализ фиксирует варианты как требование «выбрать и обосновать в ADR».
|
||||
> Рекомендация разведки — Вариант 1.
|
||||
|
||||
1. **Вариант 1 (рекомендован): `user: "1000:1000"` в docker-compose.**
|
||||
Все файлы сразу `slin:slin`, git на хосте без chown. Обязательные довески:
|
||||
- сохранить/проверить `group_add: ["999"]` (docker.sock) — **уже присутствует**;
|
||||
- обеспечить доступ uid 1000 к claude creds (`/home/slin/.claude/.credentials.json`):
|
||||
`chown 1000:1000` на хосте ИЛИ права на чтение для 1000 (задокументировать);
|
||||
- поправить SSH-маунт: `/home/slin/.orchestrator-ssh` → домашний каталог uid 1000
|
||||
(`/home/slin/.ssh`), а не `/root/.ssh`; согласовать с `HOME` в launcher;
|
||||
- проверить запуск `claude.exe` + `git` + `ssh` под uid 1000.
|
||||
|
||||
2. **Вариант 2: subprocess агента под непривилегированным uid внутри контейнера**
|
||||
(`Popen preexec_fn setuid` / `gosu`). Точечно, но сложнее; контейнер остаётся root.
|
||||
|
||||
3. **Вариант 3 (fallback, костыль): chown-хук нормализации прав после стадии**
|
||||
(`chown -R 1000:1000` worktree/доки). Лечит симптом, не корень. Применять, только
|
||||
если В1 неустранимо рвёт creds/sock.
|
||||
|
||||
## 4. Требуемые изменения (при выбранном Варианте 1)
|
||||
|
||||
### 4.1 docker-compose.yml (оба сервиса: `orchestrator`, `orchestrator-staging`)
|
||||
- Добавить `user: "1000:1000"`.
|
||||
- Сохранить `group_add: ["999"]` (НЕ удалять).
|
||||
- Изменить SSH-маунт: target `/root/.ssh` → каталог `.ssh` пользователя 1000,
|
||||
синхронно с `HOME`, который форсит launcher (`/home/slin`). То есть привести к
|
||||
единому HOME: маунт `/home/slin/.orchestrator-ssh` → `/home/slin/.ssh:ro`.
|
||||
- Маунт `/home/slin/.claude` и `.claude.json` — оставить; проверить доступ uid 1000.
|
||||
|
||||
### 4.2 Доступ к claude creds
|
||||
- Обеспечить, что `/home/slin/.claude/.credentials.json` читается uid 1000
|
||||
(на хосте — операция Owner; в ТЗ зафиксировать команду и проверку).
|
||||
|
||||
### 4.3 src/agents/launcher.py
|
||||
- Проверить, что `HOME=/home/slin` остаётся валиден под uid 1000 (домашний каталог
|
||||
существует и доступен). Менять ТОЛЬКО при доказанной необходимости.
|
||||
- Не менять CLAUDE_BIN, если запуск под 1000 подтверждён.
|
||||
|
||||
### 4.4 Dockerfile
|
||||
- Менять при необходимости (например, гарантировать существование `/home/slin` и
|
||||
права). `git config --system --add safe.directory '*'` уже есть — оставить.
|
||||
|
||||
## 5. Изменения API
|
||||
Нет.
|
||||
|
||||
## 6. Изменения схемы БД
|
||||
Нет.
|
||||
|
||||
## 7. Новые QG checks
|
||||
Нет. Существующий staging-гейт (`check_staging_status`, ORCH-35) — обязательная
|
||||
страховка перед прод-деплоем self (без изменений).
|
||||
|
||||
## 8. Артефакты pipeline, которые должны быть созданы/обновлены
|
||||
- `06-adr/ADR-NNN-<slug>.md` — выбор варианта + обоснование (мины 1–3, SSH, HOME).
|
||||
- `docs/operations/INFRA.md` — обновить блок volumes (SSH target) и, при изменении
|
||||
режима, упоминание uid рантайма.
|
||||
- `CHANGELOG.md` — запись `fix:`/`refactor:` по Conventional Commits.
|
||||
- `12-review.md`, `13-test-report.md`, `15-staging-log.md` — по ходу конвейера.
|
||||
|
||||
## 9. Порядок безопасного внедрения (требование)
|
||||
1. Живая разведка прав creds/sock/ssh ДО кода.
|
||||
2. Применить и проверить на **staging (8501)** end-to-end.
|
||||
3. Прод-рестарт контейнера под новым uid — только в окно тишины (нет активных задач).
|
||||
4. Регресс на хосте: новые tracked-артефакты `1000:1000`, `git pull` под slin без ошибок.
|
||||
55
docs/work-items/ORCH-040/03-acceptance-criteria.md
Normal file
55
docs/work-items/ORCH-040/03-acceptance-criteria.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# 03 — Критерии приёмки: ORCH-040
|
||||
|
||||
Work Item: **ORCH-040**
|
||||
|
||||
Каждый критерий имеет чёткое условие PASS/FAIL. Задача считается принятой, когда
|
||||
**все** критерии = PASS.
|
||||
|
||||
## AC-1 — Артефакты создаются под uid хоста (корневой критерий)
|
||||
- **PASS**: после прогона тестовой задачи конвейером end-to-end новые tracked-файлы
|
||||
в `/home/slin/repos/orchestrator/docs/work-items/*` и в worktree
|
||||
(`/repos/_wt/...`) имеют владельца `slin:slin` (1000:1000).
|
||||
`ls -ld /home/slin/repos/orchestrator/docs/work-items/*` → НЕ `root:root`.
|
||||
- **FAIL**: появляются новые `root:root` tracked-файлы.
|
||||
|
||||
## AC-2 — git под slin работает без ручного chown
|
||||
- **PASS**: на хосте под `slin` `git -C /home/slin/repos/orchestrator pull`,
|
||||
`git status`, `git reset` выполняются без `Permission denied` /
|
||||
`insufficient permission for adding an object`.
|
||||
- **FAIL**: любая из команд падает на правах.
|
||||
|
||||
## AC-3 — claude-агенты стартуют (preflight ok)
|
||||
- **PASS**: `claude-auth`/preflight проходит; агент конвейера запускается и
|
||||
завершается `exit_code=0` (не `Not logged in`, не отказ доступа к creds).
|
||||
- **FAIL**: агент падает на авторизации/чтении `/home/slin/.claude`.
|
||||
|
||||
## AC-4 — docker.sock доступен (деплой не сломан)
|
||||
- **PASS**: из контейнера под новым uid `docker ps` / docker-операции деплоя
|
||||
(ORCH-36 путь) работают — доступ через gid 999 сохранён (`group_add: ["999"]`).
|
||||
- **FAIL**: docker-операции отваливаются (`permission denied` на сокете).
|
||||
|
||||
## AC-5 — SSH-деплой работает
|
||||
- **PASS**: ssh-ключи читаются из домашнего каталога нового uid; деплой-хук по ssh
|
||||
(`DEPLOY_SSH_*`) выполняется.
|
||||
- **FAIL**: ssh не находит/не читает ключи (маунт указывает на чужой HOME).
|
||||
|
||||
## AC-6 — Конвейер не сломан (без регресса)
|
||||
- **PASS**: тестовая задача проходит стадии без падения запуска конвейера; доступ к
|
||||
Plane/Gitea из агентов сохранён; `pytest tests/ -q` зелёный.
|
||||
- **FAIL**: конвейер встаёт / тесты падают.
|
||||
|
||||
## AC-7 — Проверено на staging ДО прода
|
||||
- **PASS**: изменение прогнано на staging (8501), `15-staging-log.md` →
|
||||
`staging_status:` положительный; прод-рестарт выполнен в окно тишины.
|
||||
- **FAIL**: изменение применено сразу на прод без staging-прогона.
|
||||
|
||||
## AC-8 — Документация обновлена (golden source)
|
||||
- **PASS**: `docs/operations/INFRA.md` (блок volumes / SSH target / uid рантайма)
|
||||
и `CHANGELOG.md` обновлены; ADR с выбором варианта и обоснованием создан в
|
||||
`06-adr/`. Reviewer подтверждает.
|
||||
- **FAIL**: код изменён, документация/ADR не обновлены.
|
||||
|
||||
## AC-9 — Прод-контейнер не уронен вне окна тишины
|
||||
- **PASS**: рестарт self выполнен без активных задач; конвейер enduro-trails не
|
||||
пострадал.
|
||||
- **FAIL**: рестарт во время активных задач / падение прод-инстанса.
|
||||
81
docs/work-items/ORCH-040/04-test-plan.yaml
Normal file
81
docs/work-items/ORCH-040/04-test-plan.yaml
Normal file
@@ -0,0 +1,81 @@
|
||||
work_item: ORCH-040
|
||||
description: >
|
||||
Инфра-фикс: контейнер/агенты не плодят root-файлы в хостовом репо.
|
||||
Часть проверок автоматизируема через pytest (валидация compose-конфига),
|
||||
часть — обязательные ops/integration проверки на staging и хосте (manual),
|
||||
т.к. касаются прав файловой системы хоста и рантайма docker.
|
||||
|
||||
tests:
|
||||
# --- Автоматизируемые (pytest, парсинг docker-compose.yml) ---
|
||||
- id: TC-01
|
||||
type: unit
|
||||
description: >
|
||||
docker-compose.yml: оба сервиса (orchestrator, orchestrator-staging)
|
||||
имеют user: "1000:1000" (при выборе Варианта 1).
|
||||
module: tests/test_orch040_compose.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-02
|
||||
type: unit
|
||||
description: >
|
||||
docker-compose.yml: оба сервиса сохраняют group_add со значением "999"
|
||||
(доступ к docker.sock не потерян — МИНА 1).
|
||||
module: tests/test_orch040_compose.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-03
|
||||
type: unit
|
||||
description: >
|
||||
docker-compose.yml: SSH-маунт согласован с HOME агента — target каталога
|
||||
.ssh лежит под /home/slin (а не /root/.ssh), для обоих сервисов.
|
||||
module: tests/test_orch040_compose.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-04
|
||||
type: unit
|
||||
description: >
|
||||
launcher: HOME, форсимый в окружении агента и git_env, указывает на каталог,
|
||||
совместимый с SSH/claude-маунтами (/home/slin) — нет рассинхрона HOME vs uid.
|
||||
module: tests/test_orch040_compose.py
|
||||
expected: PASS
|
||||
|
||||
# --- Регресс существующего поведения ---
|
||||
- id: TC-05
|
||||
type: unit
|
||||
description: >
|
||||
Весь существующий набор тестов зелёный (нет регресса логики конвейера/launcher).
|
||||
module: tests/ # pytest tests/ -q
|
||||
expected: PASS
|
||||
|
||||
# --- Integration / ops (staging 8501, затем хост) ---
|
||||
- id: TC-06
|
||||
type: integration
|
||||
description: >
|
||||
На staging (8501) прогнать тестовую задачу конвейером end-to-end; артефакты
|
||||
worktree и docs создаются под 1000:1000 (НЕ root:root). Проверка AC-1.
|
||||
module: scripts/staging_check.py # + ls -ld на хосте
|
||||
expected: PASS
|
||||
|
||||
- id: TC-07
|
||||
type: integration
|
||||
description: >
|
||||
После staging-прогона на хосте под slin: git -C /home/slin/repos/orchestrator
|
||||
pull/status/reset без Permission denied. Проверка AC-2.
|
||||
module: manual/host-check
|
||||
expected: PASS
|
||||
|
||||
- id: TC-08
|
||||
type: integration
|
||||
description: >
|
||||
claude preflight/auth проходит под новым uid: агент стартует и завершается
|
||||
exit_code=0 (creds /home/slin/.claude читаются). Проверка AC-3 (МИНА 2).
|
||||
module: manual/staging-agent-run
|
||||
expected: PASS
|
||||
|
||||
- id: TC-09
|
||||
type: integration
|
||||
description: >
|
||||
docker.sock доступен из контейнера под uid 1000 (docker ps работает) и
|
||||
ssh-деплой-хук выполняется. Проверка AC-4, AC-5 (МИНА 1 + SSH).
|
||||
module: manual/staging-deploy-path
|
||||
expected: PASS
|
||||
Reference in New Issue
Block a user