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

22 KiB
Raw Permalink Blame History

Автоматическое сопровождение 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.

Развёртывание

  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 после завершения процесса.