Promote 2.5.0 to main-only release flow

This commit is contained in:
Виталий Литвинов
2026-04-26 12:22:19 +03:00
parent 83467ba06e
commit f483028c53
3 changed files with 14 additions and 16 deletions

View File

@@ -2,7 +2,7 @@
**Версия:** 2.5.0 **Версия:** 2.5.0
**Репозиторий:** `anten-ka/gotelegram_pro` **Репозиторий:** `anten-ka/gotelegram_pro`
**Активная ветка:** `beta` для публичной проверки; `alpha` — личная экспериментальная ветка владельца; `main` — продакшен. **Активная ветка:** `main` основной код и продакшен.
**Целевая ОС:** Ubuntu 20.04+, Debian 11+ **Целевая ОС:** Ubuntu 20.04+, Debian 11+
Этот документ описывает устройство проекта с максимальным количеством нюансов — все ловушки, на которые мы уже наступали, все причины «почему именно так», формат всех внешних интерфейсов, и checklist действий для типовых задач. Цель: чтобы новый агент мог продолжить работу без повторения ошибок и без регрессий. Этот документ описывает устройство проекта с максимальным количеством нюансов — все ловушки, на которые мы уже наступали, все причины «почему именно так», формат всех внешних интерфейсов, и checklist действий для типовых задач. Цель: чтобы новый агент мог продолжить работу без повторения ошибок и без регрессий.
@@ -43,17 +43,15 @@ tls_domain = google.com (или любой из QUICK_DOMAINS)
``` ```
anten-ka/gotelegram_pro anten-ka/gotelegram_pro
── main ← продакшен, максимально стабильная версия ── main ← основной код и продакшен
├── beta ← публичная бета для пользователей, готовых к риску и поиску багов
└── alpha ← личная alpha ветка владельца для самых ранних изменений
``` ```
**Правило коммитов:** новые изменения сначала проверяются в `alpha`, затем после ручной проверки идут в `beta`. В `main` попадает только проверенный beta-код после отдельного решения о релизе. Перед любым переносом между ветками создавай rollback tag/release для текущего состояния ветки. **Правило коммитов:** изменения идут в `main` только после локальных проверок. Перед любым рискованным переносом или force-update создавай rollback tag/release для текущего состояния `main`.
**Инструменты для коммитов:** **Инструменты для коммитов:**
- Основной путь — обычный `git commit` + `git push` в нужную ветку после локальной проверки. - Основной путь — обычный `git commit` + `git push` в нужную ветку после локальной проверки.
- Если окружение не может пушить напрямую, используй GitHub REST API с PAT из переменной окружения `GOTELEGRAM_PAT`. - Если окружение не может пушить напрямую, используй GitHub REST API с PAT из переменной окружения `GOTELEGRAM_PAT`.
- Workflow через GitHub API: `POST git/blobs` для каждого файла → `POST git/trees` (с `base_tree` от текущего HEAD) → `POST git/commits` (parents=[текущий HEAD]) → `PATCH git/refs/heads/alpha` и/или `PATCH git/refs/heads/beta` (sha=новый commit) → при необходимости `POST /releases`. - Workflow через GitHub API: `POST git/blobs` для каждого файла → `POST git/trees` (с `base_tree` от текущего HEAD) → `POST git/commits` (parents=[текущий HEAD]) → `PATCH git/refs/heads/main` (sha=новый commit) → при необходимости `POST /releases`.
- **Важно про `base_tree`:** при частичном обновлении (1-2 файла) ОБЯЗАТЕЛЬНО передавать `base_tree` — иначе дерево получится только из переданных файлов, и все остальные файлы пропадут из коммита. `base_tree` можно опускать только при коммите с полным набором файлов. - **Важно про `base_tree`:** при частичном обновлении (1-2 файла) ОБЯЗАТЕЛЬНО передавать `base_tree` — иначе дерево получится только из переданных файлов, и все остальные файлы пропадут из коммита. `base_tree` можно опускать только при коммите с полным набором файлов.
--- ---
@@ -324,7 +322,7 @@ Fallback: если по известным правилам index.html не на
## 10. История багов (не наступать на те же грабли) ## 10. История багов (не наступать на те же грабли)
Все решены в текущем HEAD (`beta`/`alpha`). Перечисление для того, чтобы новый агент не «чинил» то, что уже починено, и понимал контекст. Все решены в текущем HEAD (`main`). Перечисление для того, чтобы новый агент не «чинил» то, что уже починено, и понимал контекст.
1. `telemt.sh grep` — URL формат `telemt-x86_64-linux-gnu.tar.gz`, arch перед `linux`. Нужен `grep -iE "$arch_pattern"` + цепочка фильтров (`grep -i linux`, `grep -v sha256`, `grep gnu`, `head -1`). 1. `telemt.sh grep` — URL формат `telemt-x86_64-linux-gnu.tar.gz`, arch перед `linux`. Нужен `grep -iE "$arch_pattern"` + цепочка фильтров (`grep -i linux`, `grep -v sha256`, `grep gnu`, `head -1`).
2. `bot.py safe_edit_message` — обёртка для `query.edit_message_text`, ловит `BadRequest: message is not modified`. 2. `bot.py safe_edit_message` — обёртка для `query.edit_message_text`, ловит `BadRequest: message is not modified`.
@@ -370,7 +368,7 @@ Fallback: если по известным правилам index.html не на
- **Системные действия (v2.4.2+)** — бот реально умеет менять шаблон и домен маскировки. Хелпер `run_bot_action(action, **kwargs)` вызывает `subprocess.run(["/opt/gotelegram/install.sh", "--action=X", "--json", ...])` и парсит JSON. Два коллбэка: `cb_pro_confirm` (change-template) и `cb_lite_domain` (change-lite-domain). Оба обёрнуты в `async with _BOT_ACTION_LOCK` (глобальный `asyncio.Lock()`) — сериализуют параллельные callback'и внутри процесса бота. Входы валидируются ДО subprocess: `_TPL_ID_RE = r"^[A-Za-z0-9_-]{1,64}$"`, `_DOMAIN_RE` (RFC-like). Малформный ввод отвергается с понятным сообщением, не доходя до shell. - **Системные действия (v2.4.2+)** — бот реально умеет менять шаблон и домен маскировки. Хелпер `run_bot_action(action, **kwargs)` вызывает `subprocess.run(["/opt/gotelegram/install.sh", "--action=X", "--json", ...])` и парсит JSON. Два коллбэка: `cb_pro_confirm` (change-template) и `cb_lite_domain` (change-lite-domain). Оба обёрнуты в `async with _BOT_ACTION_LOCK` (глобальный `asyncio.Lock()`) — сериализуют параллельные callback'и внутри процесса бота. Входы валидируются ДО subprocess: `_TPL_ID_RE = r"^[A-Za-z0-9_-]{1,64}$"`, `_DOMAIN_RE` (RFC-like). Малформный ввод отвергается с понятным сообщением, не доходя до shell.
- **Поле `template_id` в config.json** — канонический ключ для текущего шаблона. Раньше (до v2.4.2) бот читал `config['template']` и писал в него же в `handle_text_message`, но `save_gotelegram_config` всегда писал `template_id` → поле статуса никогда не отображалось. Используй только `template_id`. - **Поле `template_id` в config.json** — канонический ключ для текущего шаблона. Раньше (до v2.4.2) бот читал `config['template']` и писал в него же в `handle_text_message`, но `save_gotelegram_config` всегда писал `template_id` → поле статуса никогда не отображалось. Используй только `template_id`.
- **Устанавливается** из меню `install.sh → 12) Telegram-бот → Установить`. Пользователь вводит BotFather token + свой Telegram ID, `.env` пишется в `/opt/gotelegram-bot/.env`. - **Устанавливается** из меню `install.sh → 12) Telegram-бот → Установить`. Пользователь вводит BotFather token + свой Telegram ID, `.env` пишется в `/opt/gotelegram-bot/.env`.
- **Обновляется автоматически (v2.5.0 beta+)** при повторном bootstrap/update: `auto_update_bot_if_possible` сравнивает новые файлы в `$SCRIPT_DIR/gotelegram-bot/` с установленными `/opt/gotelegram-bot/{bot.py,i18n.py,requirements.txt,lang/*.json}`. Если есть отличия и сервис уже установлен, вызывается `bot_install >/dev/null`, `.env` сохраняется, зависимости обновляются, systemd unit переписывается и `gotelegram-bot` перезапускается. Это закрывает сценарий 2.4.x → 2.5.0, где bootstrap обновлял `/opt/gotelegram/gotelegram-bot/`, но рабочий сервис продолжал запускать старый `/opt/gotelegram-bot/bot.py`. - **Обновляется автоматически (v2.5.0+)** при повторном bootstrap/update: `auto_update_bot_if_possible` сравнивает новые файлы в `$SCRIPT_DIR/gotelegram-bot/` с установленными `/opt/gotelegram-bot/{bot.py,i18n.py,requirements.txt,lang/*.json}`. Если есть отличия и сервис уже установлен, вызывается `bot_install >/dev/null`, `.env` сохраняется, зависимости обновляются, systemd unit переписывается и `gotelegram-bot` перезапускается. Это закрывает сценарий 2.4.x → 2.5.0, где bootstrap обновлял `/opt/gotelegram/gotelegram-bot/`, но рабочий сервис продолжал запускать старый `/opt/gotelegram-bot/bot.py`.
### 11.1 Non-interactive action bridge (install.sh ↔ bot) ### 11.1 Non-interactive action bridge (install.sh ↔ bot)
@@ -504,7 +502,7 @@ Traffic retention: обе CSV-истории хранятся максимум 3
import os, base64, json, urllib.request, ssl import os, base64, json, urllib.request, ssl
TOKEN = os.environ["GOTELEGRAM_PAT"] TOKEN = os.environ["GOTELEGRAM_PAT"]
REPO = "anten-ka/gotelegram_pro" REPO = "anten-ka/gotelegram_pro"
BRANCH = "beta" BRANCH = "main"
API = f"https://api.github.com/repos/{REPO}" API = f"https://api.github.com/repos/{REPO}"
headers = { headers = {
"Authorization": f"Bearer {TOKEN}", "Authorization": f"Bearer {TOKEN}",
@@ -652,7 +650,7 @@ with socket.create_connection(("95.163.176.222", 443), timeout=5) as s:
## 17. Changelog ## 17. Changelog
- **2.5.0 (2026-04-24)** — крупный maintenance pass в ветках `beta`/`alpha`: единая версия `2.5.0` в runtime и документации; удалён дефолтный PAT из `bootstrap.sh` (токен теперь только через `GOTELEGRAM_PAT`); повторный bootstrap/update автоматически обновляет уже установленный `/opt/gotelegram-bot` и перезапускает `gotelegram-bot`, сохраняя `.env`; `generate_telemt_toml` добавляет `[server.api]` на `127.0.0.1:9091` и metrics на `127.0.0.1:9090`, что нужно для управления пользователями и статистики; Telegram-бот получил меню `🔑 Keys` для `[access.users]` (добавить/отключить/включить/удалить/показать ссылку/QR/runtime info/IP-limit); добавлена локальная web-админка goTelegram Pro `gotelegram-admin` на `127.0.0.1:1984` с SSH-tunnel инструкцией в боте без отдельного web-admin токена, вкладочной UI-навигацией, иконками, блоком реальных TCP/UDP-слушателей 443, promo-modal раз в 24 часа, i18n от языка установки, ручным переключателем RU/EN, site check на HTTP 200, structured journal logs, light/dark theme, адаптивом, быстрыми switch-переключателями ключей, настройкой `[access.user_max_unique_ips]`, QR-кодами, traffic history 15m/1h/24h/month с переключением график/строки, per-user traffic history из `telemt total_octets` и stats collector restart endpoint; исправлено чтение traffic CSV в боте (header больше не ломает parsing); бот сам делает `stats_collect` перед показом статистики; `iptables` добавлен в optional deps и stats collector пытается установить его; CLI-смена шаблона теперь обновляет `config.json.template_id`, чтобы бот не показывал первый установленный шаблон; backup/restore версии `1.6` сохраняет bot `.env`, bot lang files, disabled user keys, backup schedule, web-admin server/static, custom templates, templates catalog, stats history, user stats history, shared-443 config и полноценную структуру Let's Encrypt (`live/archive/renewal`) для переезда на новый сервер; добавлен безопасный детект 3x-ui/Xray на 443 и управляемый nginx stream shared-443 dispatcher. - **2.5.0 (2026-04-24)** — крупный maintenance pass в `main`: единая версия `2.5.0` в runtime и документации; удалён дефолтный PAT из `bootstrap.sh` (токен теперь только через `GOTELEGRAM_PAT`); повторный bootstrap/update автоматически обновляет уже установленный `/opt/gotelegram-bot` и перезапускает `gotelegram-bot`, сохраняя `.env`; `generate_telemt_toml` добавляет `[server.api]` на `127.0.0.1:9091` и metrics на `127.0.0.1:9090`, что нужно для управления пользователями и статистики; Telegram-бот получил меню `🔑 Keys` для `[access.users]` (добавить/отключить/включить/удалить/показать ссылку/QR/runtime info/IP-limit); добавлена локальная web-админка goTelegram Pro `gotelegram-admin` на `127.0.0.1:1984` с SSH-tunnel инструкцией в боте без отдельного web-admin токена, вкладочной UI-навигацией, иконками, блоком реальных TCP/UDP-слушателей 443, promo-modal раз в 24 часа, i18n от языка установки, ручным переключателем RU/EN, site check на HTTP 200, structured journal logs, light/dark theme, адаптивом, быстрыми switch-переключателями ключей, настройкой `[access.user_max_unique_ips]`, QR-кодами, traffic history 15m/1h/24h/month с переключением график/строки, per-user traffic history из `telemt total_octets` и stats collector restart endpoint; исправлено чтение traffic CSV в боте (header больше не ломает parsing); бот сам делает `stats_collect` перед показом статистики; `iptables` добавлен в optional deps и stats collector пытается установить его; CLI-смена шаблона теперь обновляет `config.json.template_id`, чтобы бот не показывал первый установленный шаблон; backup/restore версии `1.6` сохраняет bot `.env`, bot lang files, disabled user keys, backup schedule, web-admin server/static, custom templates, templates catalog, stats history, user stats history, shared-443 config и полноценную структуру Let's Encrypt (`live/archive/renewal`) для переезда на новый сервер; добавлен безопасный детект 3x-ui/Xray на 443 и управляемый nginx stream shared-443 dispatcher.
- **2.4.6 (2026-04-10)** — universal `apt_lock_wait` helper: ожидание dpkg/apt lock при unattended-upgrades, исправляет установку nginx/certbot/python на свежих VPS. - **2.4.6 (2026-04-10)** — universal `apt_lock_wait` helper: ожидание dpkg/apt lock при unattended-upgrades, исправляет установку nginx/certbot/python на свежих VPS.
- **2.4.3 (2026-04-10)** — iter3-фикс: `bot_action_dispatch` оборачивается во `flock -w 30` на `/var/lock/gotelegram-bot-action.lock`. Обнаружена гонка: параллельные `change-lite-domain` получали `"no secret in config"`, потому что один процесс читал `config.json`, пока другой делал `jq ... > tmp && mv`. `util-linux` (содержит `flock`) добавлен в `critical` deps, `check_deps_present` и маппинги `apt_pkg_for_cmd`/`dnf_pkg_for_cmd`. - **2.4.3 (2026-04-10)** — iter3-фикс: `bot_action_dispatch` оборачивается во `flock -w 30` на `/var/lock/gotelegram-bot-action.lock`. Обнаружена гонка: параллельные `change-lite-domain` получали `"no secret in config"`, потому что один процесс читал `config.json`, пока другой делал `jq ... > tmp && mv`. `util-linux` (содержит `flock`) добавлен в `critical` deps, `check_deps_present` и маппинги `apt_pkg_for_cmd`/`dnf_pkg_for_cmd`.
- **2.4.2 (2026-04-10)** — реализация non-interactive `bot_action_*` в install.sh (change-template + change-lite-domain с JSON-ответом). bot.py подключает `run_bot_action()` и делает реальную работу вместо stub'ов. Критфиксы: (a) `safe_edit_message` принимает `disable_web_page_preview` (иначе TypeError в success-пути cb_pro_confirm); (b) чтение/запись `config['template_id']` вместо `config['template']` (save_gotelegram_config всегда писал `template_id`, бот смотрел не туда); (c) `bot_update_config_field` использует shell `date -Iseconds` вместо `jq now|todate` (jq 1.5 совместимость для Debian 10); (d) `asyncio.Lock _BOT_ACTION_LOCK` сериализует callback'и в процессе бота; (e) валидация `_TPL_ID_RE`/`_DOMAIN_RE` до subprocess. Полный аудит и автоустановка зависимостей: `ensure_deps` разделяет critical/optional, дедуплицирует пакеты, re-verify после install; `apt_pkg_for_cmd` и `dnf_pkg_for_cmd` мапят команды на пакеты (dig→dnsutils/bind-utils, xxd→xxd/vim-common, flock→util-linux). `check_deps_present` — быстрый чек без `apt-get update`. - **2.4.2 (2026-04-10)** — реализация non-interactive `bot_action_*` в install.sh (change-template + change-lite-domain с JSON-ответом). bot.py подключает `run_bot_action()` и делает реальную работу вместо stub'ов. Критфиксы: (a) `safe_edit_message` принимает `disable_web_page_preview` (иначе TypeError в success-пути cb_pro_confirm); (b) чтение/запись `config['template_id']` вместо `config['template']` (save_gotelegram_config всегда писал `template_id`, бот смотрел не туда); (c) `bot_update_config_field` использует shell `date -Iseconds` вместо `jq now|todate` (jq 1.5 совместимость для Debian 10); (d) `asyncio.Lock _BOT_ACTION_LOCK` сериализует callback'и в процессе бота; (e) валидация `_TPL_ID_RE`/`_DOMAIN_RE` до subprocess. Полный аудит и автоустановка зависимостей: `ensure_deps` разделяет critical/optional, дедуплицирует пакеты, re-verify после install; `apt_pkg_for_cmd` и `dnf_pkg_for_cmd` мапят команды на пакеты (dig→dnsutils/bind-utils, xxd→xxd/vim-common, flock→util-linux). `check_deps_present` — быстрый чек без `apt-get update`.
@@ -707,7 +705,7 @@ with socket.create_connection(("95.163.176.222", 443), timeout=5) as s:
## 20. Контрольные точки и инварианты ## 20. Контрольные точки и инварианты
Перед любым пушем в `alpha`/`beta`/`main`: Перед любым пушем в `main`:
1. `bash -n install.sh lib/*.sh` — синтаксис bash ОК. 1. `bash -n install.sh lib/*.sh` — синтаксис bash ОК.
2. Все новые `$()`-вызываемые функции пишут UI через `>&2`. 2. Все новые `$()`-вызываемые функции пишут UI через `>&2`.
3. Все пути к lib/ идут через `$SCRIPT_DIR/lib/...`, а `SCRIPT_DIR` — через `readlink -f`. 3. Все пути к lib/ идут через `$SCRIPT_DIR/lib/...`, а `SCRIPT_DIR` — через `readlink -f`.
@@ -718,7 +716,7 @@ with socket.create_connection(("95.163.176.222", 443), timeout=5) as s:
После пуша: После пуша:
1. Подождать пока нужная ветка обновится (GitHub API мгновенно, raw кеш ~30 сек). 1. Подождать пока нужная ветка обновится (GitHub API мгновенно, raw кеш ~30 сек).
2. На VPS: повторить bootstrap из ветки `beta` с `GOTELEGRAM_PAT` или явно передать `GOTELEGRAM_BRANCH=alpha/main`; скрипт сам скачает файлы, обновит установленный бот/админку и покажет меню. 2. На VPS: повторить bootstrap из ветки `main` с `GOTELEGRAM_PAT`; скрипт сам скачает файлы, обновит установленный бот/админку и покажет меню.
3. `telemt_status` → running. `journalctl -u telemt` → нет ошибок. Ссылка открывается в Telegram-клиенте. 3. `telemt_status` → running. `journalctl -u telemt` → нет ошибок. Ссылка открывается в Telegram-клиенте.
--- ---

View File

@@ -23,13 +23,13 @@ goTelegram Pro — это готовый менеджер прокси-серв
На чистом Ubuntu/Debian VPS под root: На чистом Ubuntu/Debian VPS под root:
```bash ```bash
export GOTELEGRAM_PAT="YOUR_PAT"; bash <(curl -sL -H "Authorization: token $GOTELEGRAM_PAT" "https://raw.githubusercontent.com/anten-ka/gotelegram_pro/beta/bootstrap.sh") export GOTELEGRAM_PAT="YOUR_PAT"; bash <(curl -sL -H "Authorization: token $GOTELEGRAM_PAT" "https://raw.githubusercontent.com/anten-ka/gotelegram_pro/main/bootstrap.sh")
``` ```
Если нужно поставить строго зафиксированный prerelease, укажи ветку/тег явно: Если нужно поставить строго зафиксированный prerelease, укажи ветку/тег явно:
```bash ```bash
export GOTELEGRAM_PAT="YOUR_PAT" GOTELEGRAM_BRANCH="v2.5.0-beta.1"; bash <(curl -sL -H "Authorization: token $GOTELEGRAM_PAT" "https://raw.githubusercontent.com/anten-ka/gotelegram_pro/v2.5.0-beta.1/bootstrap.sh") export GOTELEGRAM_PAT="YOUR_PAT" GOTELEGRAM_BRANCH="v2.5.0"; bash <(curl -sL -H "Authorization: token $GOTELEGRAM_PAT" "https://raw.githubusercontent.com/anten-ka/gotelegram_pro/v2.5.0/bootstrap.sh")
``` ```
`bootstrap.sh` скачает все файлы из приватного репозитория, создаст симлинк `/usr/local/bin/gotelegram` и запустит главное меню. Через минуту команда `gotelegram` уже будет работать откуда угодно. `bootstrap.sh` скачает все файлы из приватного репозитория, создаст симлинк `/usr/local/bin/gotelegram` и запустит главное меню. Через минуту команда `gotelegram` уже будет работать откуда угодно.
@@ -253,7 +253,7 @@ A: Сам MTProxy — да, это публичная технология из
- Баги и пожелания — issues в репозитории `anten-ka/gotelegram_pro`. - Баги и пожелания — issues в репозитории `anten-ka/gotelegram_pro`.
- Владелец: Vitalii (`anten-ka`). - Владелец: Vitalii (`anten-ka`).
- Ветки: `main` (продакшен, максимально стабильная версия), `beta` (публичная бета для пользователей, которые готовы искать баги), `alpha` (личная ветка владельца для самых ранних изменений). - Основная ветка: `main`. Старые alpha/beta/test/codex ветки закрыты, rollback-точки сохранены в релизах и тегах.
--- ---

View File

@@ -5,7 +5,7 @@
set -euo pipefail set -euo pipefail
REPO="anten-ka/gotelegram_pro" REPO="anten-ka/gotelegram_pro"
BRANCH="${GOTELEGRAM_BRANCH:-beta}" BRANCH="${GOTELEGRAM_BRANCH:-main}"
PAT="${GOTELEGRAM_PAT:-}" PAT="${GOTELEGRAM_PAT:-}"
INSTALL_DIR="/opt/gotelegram" INSTALL_DIR="/opt/gotelegram"
# Use raw.githubusercontent.com (CDN) — faster and avoids Contents API caching # Use raw.githubusercontent.com (CDN) — faster and avoids Contents API caching