22 KiB
Автоматическое сопровождение 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-релиза.
Новая цепочка выпуска состоит из двух разных состояний:
candidate— предварительный релиз Forgejo. Его видит только управляющий контур пилота. Обычные узлы используют каналstableи игнорируют такие релизы благодаря признакуprerelease=true.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.
Развёртывание
- Реализовать и протестировать разрешение официального тега, манифест, публикацию и идемпотентное продвижение.
- Опубликовать текущий код репозитория патчей и дождаться успешного Actions.
- Создать repository-scoped Forgejo-токен с
write:repository, сохранить его только в root-only runtime-env production-хоста. - Установить root-only promoter, canary-проверку и systemd timer.
- Создать новый candidate для текущего официального dev-тега, выполнить пилот
на узле
magnusи убедиться, что proven содержит те же хеши. - Проверить, что стабильный updater видит proven, а candidate игнорирует.
- Обновить проектные навыки: будущая ручная работа должна различать candidate, proven, поломку rebase и обычное обновление парка.
- Установить
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 после завершения процесса.