vpnbot-xray-patches/docs/2026-08-07-automatic-dev-release-plan.md
loop-uh 8971d9b932
Some checks failed
Test and build VPnBot Xray patches / test-and-build (push) Successful in 4m11s
Follow official Xray dev releases / candidate (push) Failing after 6m1s
Публиковать Xray для совместимого и современного CPU
2026-08-12 20:15:19 +03:00

271 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Автоматическое сопровождение dev-релизов Xray-core
## Задача
VPnBot должен получать новые официальные dev-релизы Xray-core без ручного
переписывания версии, но не имеет права сразу раздавать непроверенный бинарник
всему парку. Существующий механизм `vpnbot-active-revoke-v3` остаётся без
изменений: мы по-прежнему накладываем три собственных патча на точный
официальный исходный код и проверяем, что удаление пользователя закрывает его
уже открытые соединения, не затрагивая соседнего пользователя.
### Процессорные варианты одного proven-релиза
Номер версии и оптимизация под процессор являются двумя независимыми
измерениями одного выпуска. Самым свежим считается первый безопасный тег из
официальной Atom-ленты XTLS, но один и тот же проверенный исходник собирается в
двух вариантах для Linux amd64:
- `Xray-linux-64.zip` с `GOAMD64=v1` — обязательный совместимый вариант;
- `Xray-linux-64-v3.zip` с `GOAMD64=v3` — вариант для современных CPU, которым
виртуальная машина действительно предоставляет весь набор инструкций v3.
Манифест выпуска хранит для каждого архива не только SHA-256 и размер, но и
`goarch`, `goamd64` и точный список обязательных Linux CPU flags. Решение
принимает узловой updater по `/proc/cpuinfo`, то есть по возможностям, реально
видимым гостевой системе, а не по маркетинговому названию физического
процессора. Неполный или неизвестный набор возможностей всегда выбирает v1.
До замены рабочего файла updater запускает скачанный бинарник, проверяет
capability-маркер VPnBot и всю живую конфигурацию. После рестарта он проверяет
активность службы; при любой ошибке возвращает прежний бинарник, ресурсы и
конфигурацию. Отсутствие v3-архива в старом proven-релизе также является
штатным совместимым состоянием: узел берёт v1, а не остаётся без обновления.
Новый набор вариантов обязан создавать новую редакцию `-vpnbot.N`, даже если
официальный тег и три исходных патча не менялись. Для этого release identity
включает явную версию build profile; изменение только документации не должно
порождать новый бинарный релиз.
Production-пилот обязан установить именно v3 на canary с подтверждёнными
флагами процессора. Совместимый v1 отдельно проходит реальные процессные тесты
в CI. Proven публикуется только после обеих проверок и содержит byte-identical
архивы candidate-релиза.
Новая цепочка выпуска состоит из двух разных состояний:
1. `candidate` — предварительный релиз Forgejo. Его видит только управляющий
контур пилота. Обычные узлы используют канал `stable` и игнорируют такие
релизы благодаря признаку `prerelease=true`.
2. `proven` — обычный, не предварительный релиз. Он создаётся только из тех же
байтов, которые уже были установлены и проверены на выделенном production-
узле. После этого существующие таймеры обновления Xray могут забрать его.
## Источники истины
- Официальный GitHub `XTLS/Xray-core` владеет исходным тегом и commit.
- Официальный `releases.atom` владеет порядком опубликованных релизов. Для
discovery не используются GitHub Releases/Commits API, API-токен или
локальное зеркало Xray-core.
- `patches/series` владеет точным набором и SHA-256 наших трёх патчей.
- Манифест кандидата владеет связью между официальным тегом, официальным
commit, commit этого репозитория, патчами и контрольными суммами архивов.
- Отчёт пилота владеет фактом живой проверки конкретного кандидата.
- Forgejo release с `prerelease=false` является единственным источником
стабильного бинарника для автообновления узлов.
Файл `upstream.env` остаётся проверяемым примером и ручной фиксацией текущего
релиза. Автоматическая сборка не изменяет Git сама: она создаёт отдельный
строго проверенный build-env и манифест для найденного официального тега.
## Полный рабочий процесс
### 1. Обнаружение официального выпуска
Forgejo Actions по расписанию и по ручному запуску читает официальный
`https://github.com/XTLS/Xray-core/releases.atom`. Берётся первая безопасная
ссылка на опубликованный официальный тег формата `vN.N.N`; feed одинаково
принимает обычные и официальные prerelease/dev-выпуски, поэтому отдельный
GitHub-флаг prerelease для доверия не нужен.
Затем Actions создаёт временный пустой Git-каталог, выполняет shallow fetch
ровно этого тега из официального `XTLS/Xray-core.git`, разрешает его в точный
40-символьный commit и читает из commit-объекта время и `go.mod`. Временный
каталог удаляется после discovery. Постоянная или полная копия Xray-core в
Forgejo и на production-хосте не создаётся; ветка `main`, GitHub
Releases/Commits API и `raw.githubusercontent.com` в выборе версии не
участвуют.
Позднейший `prepare-source.sh` заново получает тот же точный тег и обязан
доказать совпадение commit перед наложением патчей. Если официальный тег между
discovery и подготовкой исходника был перемещён, выпуск останавливается.
Если для сочетания «официальный commit + SHA-256 набора патчей» уже существует
`proven`-манифест, запуск завершается как штатный `no-op`. Если существует тот
же кандидат, повторный запуск проверяет его идентичность и тоже не создаёт
дубликат.
### 2. Подготовка и проверка
Официальный исходник загружается по точному тегу и сверяется с ожидаемым
commit. Затем последовательно проверяются SHA-256 и накладываются ровно три
патча. Любой конфликт патча, лишний патч, пропавший capability-маркер,
непроходящий Go-тест или ошибка сборки останавливает выпуск до публикации.
Тесты включают unit- и real-process-сценарии для VLESS, Trojan, VMess и
Shadowsocks. В них пользователь A удаляется при открытом соединении,
соединение A должно закрыться, а соединение B — продолжить работу.
### 3. Воспроизводимая сборка кандидата
Три Linux-архива собираются с одинаковым `SOURCE_DATE_EPOCH`, полученным из
времени официального commit. `geoip.dat` и `geosite.dat` берутся из
официального Xray-архива того же тега и проверяются по опубликованному
официальному `.dgst`; подвижная ветка стороннего репозитория больше не влияет
на результат.
В бинарник записывается будущий `proven`-тег. Поэтому кандидат и окончательный
релиз содержат один и тот же бинарник; продвижение не пересобирает и не меняет
ни одного байта.
Рядом с архивами публикуется `vpnbot-xray-release-manifest.json`. Он содержит:
- официальный репозиторий, тег, commit и время commit;
- commit репозитория патчей;
- capability `vpnbot-active-revoke-v3`;
- candidate- и proven-теги;
- SHA-256 каждого патча и каждого публикуемого файла;
- версию схемы манифеста.
### 4. Публикация candidate
Actions сначала создаёт скрытый Forgejo draft с `prerelease=true`, загружает и
повторно сверяет точные архивы, файлы `.dgst` и манифест и только затем
публикует candidate последним API-вызовом. Для этого используется короткоживущий
`FORGEJO_TOKEN`, ограниченный текущим репозиторием. В workflow нет SSH-ключей
production-узлов и постоянного Forgejo-токена.
### 5. Живой production-пилот
Root-only таймер на production-хосте опрашивает только candidate-релизы. Он
берёт первый ещё не продвинутый кандидат, проверяет схему манифеста и SHA-256
всех загруженных файлов, после чего устанавливает точную версию на явно
указанный canary-узел штатным `vpnbot-xray-core-updater`.
После установки проверяются:
- совпадение заявленной версии и capability;
- валидность существующей конфигурации;
- активность `vpnbot-xray.service`;
- изолированный real-process-сценарий на самом canary: отдельный Xray-процесс
на loopback, два временных VLESS-пользователя, два непрерывных TCP-потока,
удаление только пользователя A через Xray API, закрытие A не позднее 10
секунд и продолжение B;
- отсутствие оставшихся тестовых процессов и временных конфигураций.
Изолированный сценарий не добавляет пользователей в боевые inbound и не
меняет production-конфигурацию. Он запускает уже установленный кандидат тем же
бинарником, но на случайных loopback-портах.
Если установка или проверка не проходит, `proven` не создаётся. При сбое после
успешной установки управляющий контур возвращает canary на предыдущий точный
стабильный релиз штатным updater и сохраняет диагностический отчёт.
### 6. Продвижение proven
Управляющий контур формирует JSON-отчёт пилота с candidate-тегом, хешем
манифеста, узлом, временем, предыдущей и установленной версиями и результатами
проверок. Затем через Forgejo API создаётся скрытый draft с proven-тегом.
Все архивы и `.dgst` скачиваются из candidate-релиза, повторно сверяются с
манифестом и без пересборки загружаются в proven-релиз. Манифест и отчёт пилота
тоже прикладываются. Candidate повторно проверяется после загрузки proven-
файлов; только затем draft становится видимым стабильным релизом. Если
proven-тег уже существует, повторный запуск обязан
доказать его полную идентичность; несовпадение считается конфликтом и
завершает операцию безопасной ошибкой.
### 7. Распространение
Обычные узлы остаются на `XRAY_CORE_RELEASE_CHANNEL=stable` и
`XRAY_CORE_VERSION=latest`. Их существующий updater пропускает Forgejo-
релизы с `prerelease=true`, поэтому кандидат не может случайно попасть во весь
парк. После появления proven-релиза штатные таймеры устанавливают его с
проверкой SHA-256, capability, конфигурации, перезапуском и автоматическим
rollback при ошибке.
## Гонки и повторные запуски
- Workflow имеет один `concurrency`-ключ и не отменяет уже начатую сборку.
- Production-промоутер использует локальную файловую блокировку и не допускает
два одновременных пилота.
- Теги вычисляются детерминированно из существующих релизов. Конфликт уже
занятого тега никогда не обходится перезаписью или удалением.
- Во всех сетевых ответах проверяются типы, ожидаемые имена, commit и хеши.
- Между проверкой кандидата и созданием proven повторно загружается release и
подтверждается неизменность candidate-манифеста.
- Публикация proven происходит только после завершённого отчёта пилота; draft
и prerelease не считаются стабильным состоянием.
## Сбои и безопасное поведение
- GitHub release-feed или официальный Git transport недоступен: выпуск
откладывается, текущий proven остаётся последним.
- Feed указывает на небезопасную ссылку, неизвестный XML или тег не формата
`vN.N.N`: запись игнорируется, а при отсутствии безопасной записи выпуск
останавливается.
- Новый тег исчез или перемещён: commit не совпадает, сборка прекращается.
- Патчи больше не применяются: кандидат не публикуется, это сигнал для ручной
адаптации патчей, а не повод перейти на чистое upstream-ядро.
- Сборка или тесты упали: кандидат не публикуется.
- Candidate опубликован не полностью: промоутер отвергает его по отсутствующим
файлам или хешам.
- Canary недоступен: продвижение откладывается без изменения парка.
- Canary не стартовал: updater возвращает предыдущий бинарник.
- Живой тест отзыва не прошёл: canary возвращается на предыдущий proven, новый
stable-релиз не появляется.
- Forgejo недоступен после пилота: отчёт сохраняется локально, следующий запуск
повторяет идемпотентное продвижение того же кандидата.
## Операторские уведомления
Отдельный root-only наблюдатель читает три уже существующих источника истины и
не вмешивается в выпуск:
- последний запуск `candidate.yml` на `main` в Forgejo Actions;
- опубликованные candidate-манифесты и наличие связанного proven;
- JSON-состояния production-промоутера, включая
`failed_rolled_back` и `failed_rollback_failed`.
Подтверждённая проблема отправляется оператору в Telegram один раз, затем не
чаще заданного интервала напоминания. Незавершённый повторный workflow или
canary имеет состояние `pending` и не создаёт ложного сообщения о
восстановлении. Восстановление публикуется только после успешного workflow,
появления exact proven или исчезновения canary-сбоя после успешного
продвижения. Долговечное состояние доставки отделено от манифеста, proof и
решения о публикации релиза.
Полный контракт дедупликации, безопасности токена и проверки описан в
[`2026-08-07-release-telegram-alert-plan.md`](2026-08-07-release-telegram-alert-plan.md).
## Развёртывание
1. Реализовать и протестировать разрешение официального тега, манифест,
публикацию и идемпотентное продвижение.
2. Опубликовать текущий код репозитория патчей и дождаться успешного Actions.
3. Создать repository-scoped Forgejo-токен с `write:repository`, сохранить его
только в root-only runtime-env production-хоста.
4. Установить root-only promoter, canary-проверку и systemd timer.
5. Создать новый candidate для текущего официального dev-тега, выполнить пилот
на узле `magnus` и убедиться, что proven содержит те же хеши.
6. Проверить, что стабильный updater видит proven, а candidate игнорирует.
7. Обновить проектные навыки: будущая ручная работа должна различать
candidate, proven, поломку rebase и обычное обновление парка.
8. Установить `vpnbot-xray-release-alert.timer`, отправить один test-message и
подтвердить, что здоровый снимок даёт три состояния `healthy` без
аварийного сообщения.
## Критерий готовности
Система считается завершённой, когда новый официальный dev-тег без изменения
патчей автоматически проходит цепочку
`GitHub tag -> patch/test/build -> candidate -> canary -> proven`, а узлы на
стабильном канале никогда не видят candidate. При любой неоднозначности или
ошибке цепочка останавливается до proven и сохраняет работающий предыдущий
релиз. Оператор получает дедуплицированное Telegram-уведомление об этой
остановке и подтверждение после реального восстановления источника истины.
Discovery считается независимым от GitHub API, только если в release-коде нет
ссылок на `api.github.com` и `raw.githubusercontent.com`, новый тег разрешается
через `releases.atom` плюс точный Git-fetch, а временный shallow-каталог не
остаётся источником или хранилищем Xray-core после завершения процесса.