docs: README по требованиям к оформлению и демо-сервисы examples/ (#19)
CI / ruff · mypy · pytest (pull_request) Successful in 26m33s
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:
@@ -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, процесс
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user