docs: README по требованиям к оформлению и демо-сервисы examples/ (#19)
CI / ruff · mypy · pytest (pull_request) Successful in 26m33s

- README: цели и задачи, что реализовано, развёртывание (локально за 5 минут
  и полный стек), переменные, команды и данные, используемые API,
  ограничения и лимиты, что не сделано, структура репозитория
- examples/: hello (healthy + материал для grep/агента), crash (💥 и 🔁),
  cpu_hog (🔥), unhealthy (🩺), syntax_error/lint_fail для коммита,
  вопросы агенту и атаки; make demo-up / demo-down в том же Compose-проекте
- make local-proxy: read-only Docker API для `make run`
- ARCHITECTURE: краш при restart-политике и гистерезис алертов

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 15:56:47 +03:00
co-authored by Claude Opus 5.5
parent 79ea5ce2a5
commit d246296dd2
14 changed files with 417 additions and 14 deletions
+199 -9
View File
@@ -1,14 +1,204 @@
# tgit
# tgit — git в Телеграме
Телеграм-бот для загрузки кода в репозиторий и работы с ним. Простыми словами — расширенный git внутри Telegram-бота.
Бот принимает `.py`-файлы и коммитит их в репозиторий на SourceCraft, где автоматически запускается CI/CD;
сообщает статус пайплайна, присылает алерты, отдаёт логи и отвечает на вопросы по ним через LLM.
Телеграм-бот для команды, которая ведёт общий репозиторий небольших Python-сервисов. Прямо из чата можно поправить
код и закоммитить его, посмотреть, живы ли контейнеры, поискать по логам — своим grep или вопросом LLM-агенту, —
и получать алерты, когда что-то упало.
Учебный проект, курс Python, НИУ ВШЭ.
Основной репозиторий и задачи — [Gitea `HSE/tgit`](https://gitea.24studbank.ru/HSE/tgit);
[SourceCraft](https://sourcecraft.dev/rogachevegorushka/tgit) — зеркало.
- ТЗ: [`docs/SPEC.md`](docs/SPEC.md)
- Архитектура: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)
- Как работаем: [`docs/dev/WORKFLOW.md`](docs/dev/WORKFLOW.md)
| Документ | О чём |
|---|---|
| [`docs/SPEC.md`](docs/SPEC.md) | ТЗ: требования A-, M-, C-, S-, L-, AL- |
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | модули, потоки данных, хранилище |
| [`docs/DECISIONS.md`](docs/DECISIONS.md) | решения ADR-001…015 с альтернативами |
| [`docs/dev/DEPLOY.md`](docs/dev/DEPLOY.md) | CI/CD и деплой на сервер |
| [`examples/README.md`](examples/README.md) | демо-сервисы и сценарии для проверки |
Основной репозиторий и задачи — [Gitea `HSE/tgit`](https://gitea.24studbank.ru/HSE/tgit); [SourceCraft](https://sourcecraft.dev/rogachevegorushka/tgit) — зеркало с CI/CD.
---
## 1. Цели и задачи
**Цель** — сделать так, чтобы мелкие правки в общем коде и разбор инцидентов не требовали ноутбука с git и SSH:
всё, что обычно делают в терминале, доступно из Телеграма, причём безопасно для сервера.
**Задачи:**
- пускать в бота только своих — по одноразовому QR-приглашению, без регистрации;
- редактировать файлы репозитория и коммитить их из чата с проверкой до пуша;
- показывать состояние контейнеров и запускать проверки здоровья по кнопке;
- давать логи — хвост, grep и вопрос на естественном языке, — не открывая shell и не отдавая логи в LLM;
- сообщать всей команде о падениях и перегрузках без спама;
- защищаться от «случайных людей» и попыток взлома через бота.
## 2. Что реализовано
| Раздел | Возможности | Требования |
|---|---|---|
| **Доступ** | вход только по одноразовому QR (TTL 24 ч), роли админ/участник, отзыв доступа сразу, молчание на перебор токенов (> 5 неудач в час) | A-1…A-8 |
| **📝 Коммит** | навигация по папкам, просмотр файла, новый файл/папка, замена (текстом или документом), удаление; проверка имени, размера, UTF-8 и синтаксиса Python; черновик до 50 изменений; сообщение коммита; push с проверкой конфликтов и «Перезаписать» | C-1…C-34 |
| **🩺 Статус** | все контейнеры 🟢/🟡/🔴/⚪; карточка — health, аптайм, рестарты, CPU/RAM от лимита, ревизия и время деплоя; «🩺 Запустить проверки» — 7 независимых проверок с таймаутами | S-1…S-4 |
| **📜 Логи** | хвост 50/200 строк или 5 мин/1 ч/24 ч; свой grep (`-i -v -E -c -C N`), выполняется в Python, не в shell; длинный ответ — файлом; журнал поисков | L-1…L-6 |
| **🤖 Агент** | вопрос словами → фильтр → LLM-страж → LLM строит только `LogQuery` → валидация → grep; показывает построенную команду и строки; атака — отказ и 🛡 админам; 30 вопросов в сутки | L-10…L-17 |
| **🚨 Алерты** | 💥 краш, 🧠 OOM, 🔁 цикл рестартов, 🩺 unhealthy, 🔥 перегрузка, 💾 мало места, 🔌 Docker недоступен, 🛡 атака; всем участникам, с хвостом лога и кнопками; повторы — счётчик, «✅ восстановлено» ответом; список за 7 дней | AL-1…AL-6 |
| **CI/CD бота** | Gitea Actions: ruff, mypy strict, миграции up/down/up на PostgreSQL, pytest с порогом покрытия 80 %; автодеплой `dev` на сервер с проверкой health | ADR-015 |
Качество: 296 тестов, покрытие 92 %, `mypy --strict`, `ruff`. Telegram в тестах — фейковая сессия aiogram,
Docker — фейковый Engine API на `httpx.MockTransport`, LLM — сценарный фейк.
## 3. Развёртывание и запуск
### Требования
- Python 3.12 и [uv](https://docs.astral.sh/uv/) — для запуска без Docker и тестов;
- Docker 24+ с Compose v2 — для полного стека;
- токен бота от [@BotFather](https://t.me/BotFather) и ваш Telegram ID (узнать — у [@userinfobot](https://t.me/userinfobot));
- для агента логов — OpenAI-совместимый LLM с structured output (`response_format: json_schema`).
Один токен — один запущенный экземпляр: Telegram отдаёт обновления только одному процессу.
### Вариант А — локально за 5 минут (без Docker для бота)
```bash
git clone https://gitea.24studbank.ru/HSE/tgit.git && cd tgit
make install # uv sync
cp .env.example .env # впишите TELEGRAM_BOT_TOKEN и ADMIN_IDS
make demo-repo # локальный репозиторий загрузок из шаблона
# → допишите напечатанную строку GIT_UPLOADS_URL=... в .env
make run # бот запущен, база — SQLite ./tgit.db
```
Чтобы заработали «Статус», «Логи» и алерты, нужен Docker API:
```bash
make local-proxy # read-only прокси Docker на 127.0.0.1:23750
echo DOCKER_URL=http://127.0.0.1:23750 >> .env
make demo-up # демо-сервисы: здоровый, падающий, CPU-hog, unhealthy
make run
```
### Вариант Б — полный стек в Docker
```bash
cp .env.example .env # токен, ADMIN_IDS, репозиторий загрузок и ключ (см. ниже)
make up # бот + PostgreSQL 16 + docker-socket-proxy
make demo-up # по желанию: демо-сервисы рядом с ботом
make logs # логи бота
```
В Docker бот ходит в репозиторий загрузок по SSH: нужен отдельный репозиторий (шаблон —
[`infra/uploads-template/`](infra/uploads-template/)) и deploy-ключ с правом записи. Ключ передаётся в
`GIT_SSH_KEY_B64` (`base64 -w0 <ключ>`): смонтированный файл контейнер прочитать не сможет.
### Сервер
CD из Gitea Actions разворачивает `dev` на сервер скриптом `infra/deploy/deploy.sh` — его же можно запускать
руками для любого хоста. Подробно — в [`docs/dev/DEPLOY.md`](docs/dev/DEPLOY.md).
### Переменные окружения
Полный список с комментариями — [`.env.example`](.env.example). Секреты хранятся только в `.env`, в git не попадают.
| Переменная | Обязательна | Что задаёт |
|---|---|---|
| `TELEGRAM_BOT_TOKEN` | да | токен бота |
| `ADMIN_IDS` | да | Telegram ID первых администраторов через запятую |
| `TELEGRAM_PROXY_URL` | нет | HTTP/SOCKS-прокси до Telegram (если сервер не видит api.telegram.org) |
| `GIT_UPLOADS_URL` | да | репозиторий загрузок: путь, `ssh://…` или `git@…` |
| `GIT_SSH_KEY_B64` / `GIT_SSH_KEY_PATH` | для SSH | deploy-ключ бота |
| `DATABASE_URL` | нет | по умолчанию SQLite; в Compose — PostgreSQL |
| `DOCKER_URL` | нет | docker-socket-proxy; без него «Статус», «Логи» и алерты отвечают «Docker недоступен» |
| `LLM_PROVIDER`, `LLM_BASE_URL`, `LLM_MODEL`, `LLM_API_KEY` | нет | LLM для агента; при `mock` агент выключен |
### Проверки
```bash
make lint # ruff + mypy --strict
make test # pytest
make cov # pytest с покрытием (порог 80 %)
```
## 4. Входные и выходные данные
### Команды и кнопки
| Ввод | Что происходит |
|---|---|
| `/start <токен>` (ссылка из QR) | регистрация по приглашению, главное меню |
| `/start`, `/menu` | главное меню; из любого шага диалога |
| `/help` | справка |
| 📝 Коммит · 🩺 Статус · 📜 Логи · 🚨 Алерты | разделы; у админа ещё 👥 Участники (приглашения, отзыв) |
Внутри разделов — инлайн-кнопки. Текстом бот принимает имя файла или папки, содержимое файла (текстом, в том числе
в блоке ```` ``` ````, или документом до 100 КБ), сообщение коммита, выражение grep и вопрос агенту.
### Выходные данные
- **В Телеграме**: экраны разделов, файлы (`.log` для длинных результатов, исходник для больших файлов),
QR-приглашения PNG, алерты.
- **В репозитории загрузок**: коммиты от `tgit-bot` с автором из Телеграма; push в `main` запускает CI репозитория.
- **В БД** (13 таблиц, миграции Alembic): участники и приглашения, черновики, состояние диалогов, снапшоты
контейнеров, алерты и их доставки, журналы поисков по логам и вопросов агенту.
### Используемые API
| API | Зачем | Как |
|---|---|---|
| Telegram Bot API | весь интерфейс | aiogram 3, long polling |
| git (SSH) | чтение и коммиты в репозиторий загрузок | `git` подпроцессом со своим ключом, без shell |
| Docker Engine API | контейнеры, stats, логи | только GET через `docker-socket-proxy` |
| OpenAI-совместимый `/chat/completions` | страж и планировщик агента | httpx, `response_format: json_schema` |
| SourceCraft REST API | статус прогонов CI репозитория загрузок | httpx, клиент готов, в UI — #11 |
## 5. Ограничения и особенности
**Безопасность:**
- Docker-сокет есть только у прокси, и тот пропускает лишь `GET /containers/*`. Бот показывает только контейнеры с меткой
`tgit.managed=true` и отказывает по чужому id ещё до запроса: на сервере живут и другие проекты.
- grep разбирается `shlex.split` и выполняется модулем `regex` с таймаутом на строку и общим бюджетом 3 с;
катастрофический шаблон вроде `(a|aa)+$` бота не вешает.
- Агент: логи в LLM **не передаются** (только вопрос и имена контейнеров), поэтому prompt injection из логов невозможен.
LLM может вернуть только `LogQuery` — контейнер из белого списка, период ≤ 7 дней, шаблон ≤ 200 символов без
вложенных квантификаторов. Даже обманутый страж даёт в худшем случае медленный grep.
- Пути `.git/`, `.sourcecraft/`, `.tgit/` и `ruff.toml` из Телеграма не редактируются. Бот проверяет синтаксис
до пуша, но код сервисов не исполняет.
**Лимиты:**
| Что | Лимит |
|---|---|
| файл из Телеграма | 100 КБ, UTF-8 |
| черновик | 50 изменений |
| push | 20 в час на участника |
| шаблон grep | 200 символов; вывод — 500 строк |
| чтение логов | 50 000 строк и 5 МБ (новейшие) |
| вопрос агенту | 500 символов, 30 в сутки |
| повтор алерта | в течение 10 мин — счётчик, а не новое сообщение |
**Что пока не сделано** (открытые задачи):
- запуск сервисов из репозитория загрузок в песочнице (`--cap-drop ALL`, read-only FS, лимиты) и перезапуск из бота —
`tgit-runner`, #13. Сейчас сервисы поднимаются Compose, как в `examples/`;
- уведомления о прогонах CI/CD репозитория загрузок и алерты 📦/⛔ — #11, ждут возврата к SourceCraft;
- «🔕 Тишина на час» для алертов (P2);
- prod-окружение: нужен отдельный бот, деплой `main` пропускается, пока его нет.
## Структура репозитория
```
app/
access/ приглашения, QR, проверка доступа
bot/ диспетчер, меню, роутеры разделов, FSM в БД
repo/ клон репозитория загрузок, валидация, черновики, push
runtime/ Docker API, проверки, снапшоты
logs/ grep-движок и журнал
agent/ фильтр, страж, планировщик, схема LogQuery
alerts/ детекторы, сервис алертов, рассылка, монитор
llm/ провайдеры: OpenAI-совместимый, mock
sourcecraft/ клиент API прогонов
db/ модели, миграции Alembic, очистка
config/ тексты интерфейса, пороги проверок и алертов, правила и промпты агента
tests/ pytest; фейки Telegram, Docker и LLM
examples/ демо-сервисы и сценарии
infra/ деплой на сервер, шаблон репозитория загрузок
docs/ ТЗ, архитектура, ADR, процесс
```