diff --git a/CHANGELOG.md b/CHANGELOG.md index 64993d0..0d6896a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,32 +1,36 @@ # История изменений -## 2.2.5 / OPKG 2.2.5 — 2026-07-31 - -- публичный OPKG-feed и документация опубликованы атомарно; обычная и no-cache загрузки IPK совпали с `Packages`; -- переход `2.1.1-2 → 2.2.5` успешно завершён через WebUI на реальном Keenetic; -- исправлено чтение `SHA256sum` из сжатого локального `src/gz` и передача `BRORAY_OPKG_LISTS_DIR` фоновому worker старого WebUI; -- перед установкой удаляются старые автоматические копии и управляемый мусор, затем создаётся одна актуальная проверенная копия только в `/tmp`; -- BROray позиционируется как полноценный клиент Xray для современных Keenetic и Netcraze, а не только менеджер конфигураций; -- финализирован адаптивный WebUI для компьютера, планшета и телефона; -- добавлена отдельная страница DNS-over-TLS, предустановки Яндекс DNS и поддержка вложенного running-config Keenetic; -- исправлены фактическая сверка DoT/DoH, лимит восьми серверов, сообщения этапа ошибки и транзакционный откат; -- добавлена отдельная кнопка обновления Xray; обновление и переустановка разделены; -- исправлен JSON backend проверки обновления и безопасной очистки BROray; -- маршруты разделены на обзор, свои маршруты и готовые маршруты; -- добавлены подпункты раздела маршрутов в меню; -- девять готовых наборов работают через один агрегированный summary; -- пользовательские BAT анализируются как текст и никогда не выполняются; -- единое окно прогресса открывается сразу, поддерживает остановку после текущего маршрута и продолжение; -- в покое polling маршрутов сокращён, скрытые вкладки не опрашивают backend, параллельные запросы не накапливаются; -- сохранён единый реестр владельцев общих маршрутов; -- добавлены восстановительная переустановка, безопасная очистка, технические журналы и полный жизненный цикл BROray; -- релиз собран из проверенной контрольной точки реального роутера. +## 2.2.6 / OPKG 2.2.6 — release candidate + +- исправлена несовместимость контракта резервной копии между updater и пакетным `preinst`; +- `preinst` распознаёт как полную копию `/opt` с `broray/...`, так и внутреннюю rootless-копию; +- функция учёта состояния служб завершается явным `return 0`; +- остановленная `S28broray-subscriptions` больше не считается ошибкой резервного копирования; +- updater передаёт `BRORAY_OPKG_CLEANUP_DONE=1` и не допускает повторную очистку или вторую копию; +- полный вывод OPKG, `preinst` и `postinst` сохраняется и показывается перед откатом; +- правила релиза обновлены до версии 1.3: неизменяемый кандидат → физический WebUI-тест → продвижение тех же байтов; +- добавлена обязательная проверка повторного обновления после отката и внешних HTTP/SHA-прав установочных файлов; +- кандидат не публикуется в стабильный канал до подтверждённого физического теста. + +## 2.2.5 / OPKG 2.2.5 — ОТОЗВАН 2026-07-31 + +- пакет и OPKG-индекс были побайтово согласованы, но реальное обновление с `2.2.0-2` завершилось ошибкой; +- updater создавал полную копию `/opt` с корнем `broray/`, а `preinst` принимал только rootless-корни `bin/`, `lib/`, `web-new/`, `config/`; +- после отката повторная попытка могла остановиться из-за отсутствующего явного `return 0` в функции учёта служб; +- релиз был полностью удалён из публичного OPKG, установочные файлы перемещены в серверный карантин, документация возвращена к 2.2.4; +- прежнее утверждение об успешном физическом WebUI-обновлении было ошибочным и отменено. + +## 2.2.4 / OPKG 2.2.4 — текущий стабильный + +- стабильный публичный релиз после отзыва 2.2.5; +- WebUI `WebUI-2.2.0-r2`; +- сохранён как базовая версия публичного канала и пакет возврата. ## 2.2.0 / OPKG 2.2.0-2 — полевой кандидат - полевое обновление на реальном Keenetic; -- первоначальная отдельная страница DNS-over-TLS; -- подготовка новой архитектуры маршрутов и серии принятых hotfix. +- отдельная страница DNS-over-TLS; +- новая архитектура маршрутов и принятые hotfix. ## 2.1.1-2 — 2026-07-27 diff --git a/README.md b/README.md index 9fd688e..8c2dc07 100644 --- a/README.md +++ b/README.md @@ -1,144 +1,60 @@ # BROray -**BROray — полноценный клиент Xray для современных маршрутизаторов Keenetic и Netcraze.** Это не только менеджер конфигураций: BROray устанавливает и обслуживает Xray, принимает подписки и отдельные подключения, выбирает активный сервер, создаёт штатный прокси-интерфейс `ProxyN`, управляет маршрутами, DNS-over-TLS, обновлениями и диагностикой через локальный авторизованный WebUI. +**BROray — полноценный клиент Xray для современных маршрутизаторов Keenetic и Netcraze.** BROray устанавливает и обслуживает Xray, принимает подписки и отдельные подключения, выбирает активный сервер, создаёт штатный `ProxyN`, управляет маршрутами, DNS-over-TLS, обновлениями и диагностикой через локальный авторизованный WebUI. -## Статус релиза +## Статус релизов -**BROray 2.2.5 / OPKG 2.2.5 опубликован 31 июля 2026 года и успешно установлен на реальный Keenetic полным пользовательским путём через WebUI.** Проверенный переход выполнен с установленной версии `2.1.1-2`: `BROray → Проверить обновление → Установить обновление`. +- **Стабильный публичный релиз:** BROray `2.2.4`, OPKG `2.2.4`, WebUI `WebUI-2.2.0-r2`. +- **BROray 2.2.5 отозван 31 июля 2026 года.** На физическом роутере обнаружены несовместимые форматы резервной копии между updater и `preinst`, а также ошибочный код возврата функции учёта служб. Пакет, установщики и запись OPKG удалены из публичного канала. +- **BROray 2.2.6 находится в статусе release candidate.** Он не считается опубликованным релизом до прохождения полного физического теста через WebUI теми же неизменяемыми байтами. -Версия 2.2.4 отозвана. В 2.2.5 исправлены обязательный порядок очистки и резервного копирования, preflight свободного места и чтение SHA-256 из OPKG `src/gz`, включая фоновый worker старого WebUI. +## Что исправляет 2.2.6 -## Текущий релиз +- `preinst` распознаёт два допустимых контракта резервной копии: полную копию `/opt` с корнем `broray/` и внутреннюю копию с корнями `bin/`, `lib/`, `web-new/`, `config/`; +- updater явно завершает учёт служб кодом `0`, поэтому остановленная `S28broray-subscriptions` не ломает создание резервной копии; +- updater передаёт `BRORAY_OPKG_CLEANUP_DONE=1`, исключая повторную очистку и вторую резервную копию в `preinst`; +- при ошибке показываются последние строки полного журнала `opkg install`/`preinst`/`postinst` до автоматического отката; +- публичные скрипты должны публиковаться читаемыми Nginx и проверяться внешней загрузкой с SHA-256; +- правила релиза обновлены до версии 1.3: сначала неизменяемый кандидат, затем физический WebUI-тест, затем продвижение ровно тех же байтов. -- Приложение: **BROray 2.2.5** -- Пакет OPKG: **2.2.5** -- Архитектура пакета: **aarch64-3.10** -- WebUI: **WebUI-2.2.0-r3** -- Xray в пакете: **26.7.11**, SHA-256 `dd3ba298aa32af9442163ee791d54f562bd89aa860fed1d0c47306fb019c1e64` +## Обязательная проверка кандидата 2.2.6 -Релиз собран из проверенной контрольной точки реального Keenetic от 30 июля 2026 года. Публикация OPKG и сайта завершилась со статусом `success`, кодом `0`; публичные `Packages`, обычная и no-cache загрузки IPK совпали. Полевое обновление до 2.2.5 через WebUI завершилось успешно 31 июля 2026 года. +1. Сборка кандидата из точных отозванных байтов 2.2.5, сохранённых в серверном карантине. +2. Публикация только в закрытый staging-канал. +3. Обновление через установленный WebUI с `2.2.0-2` и `2.2.4`. +4. Тест с остановленной `S28broray-subscriptions`. +5. Принудительная ошибка установки, автоматический откат и успешная повторная попытка. +6. Чистая установка на физическом роутере. +7. Проверка пяти служб, WebUI, Xray, ProxyN, DNS-over-TLS, маршрутов и пользовательских данных. +8. Только после отчёта `PASS` — атомарное продвижение тех же байтов из staging в публичный OPKG. + +Подробности: [`docs/RELEASE-2.2.6.md`](docs/RELEASE-2.2.6.md) и [`docs/RELEASE-REQUIREMENTS.md`](docs/RELEASE-REQUIREMENTS.md). ## Основные возможности - локальный авторизованный WebUI для компьютера, планшета и телефона; - импорт VLESS, VMess, Trojan и Hysteria2; - подписки, отдельные серверы, проверка качества и автоматическое переключение; -- полный жизненный цикл Xray: запуск, остановка, перезапуск, проверка конфигурации, диагностика, обновление и безопасная переустановка; -- создание и восстановление штатного интерфейса KeeneticOS/NDMS `ProxyN`; -- свои BAT-маршруты и девять готовых наборов маршрутов; -- единый реестр владельцев маршрутов: общие маршруты не удаляются, пока нужны другому набору; -- единое окно фактического прогресса, безопасная остановка после текущего маршрута и продолжение; -- DNS-over-TLS с TLS/SNI-проверкой, Яндекс DNS, сохранением внешних DoT/DoH и транзакционным откатом; -- безопасное обновление BROray: удаление старых автоматических копий и мусора, одна проверенная актуальная копия только в `/tmp`, точный preflight места и автоматическое восстановление; -- восстановительная переустановка, технический журнал и безопасная очистка управляемых файлов. - -## Требования к роутеру +- полный жизненный цикл Xray; +- создание и восстановление `ProxyN`; +- свои BAT-маршруты и девять готовых наборов; +- единый реестр владельцев общих маршрутов; +- DNS-over-TLS с транзакционным откатом; +- восстановительная переустановка, технический журнал и безопасная очистка. -Подробности: [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md). +## Требования -Кратко: +См. [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md). Основная архитектура пакета — `aarch64-3.10`; требуется Entware, записываемый `/opt` и доступ к Entware root shell. -1. Современный Keenetic или Netcraze с `aarch64/arm64` и архитектурой Entware `aarch64-3.10`. -2. Установленные компоненты **Open Package support** и **Proxy client**. -3. Установленный Entware/OPKG, доступная для записи точка `/opt` и SSH-доступ именно к Entware root shell. Системный компонент **SSH server** не обязателен, если доступ уже предоставляет Entware OpenSSH/Dropbear. -4. Для страницы DNS-over-TLS — компонент **DNS-over-TLS proxy**. -5. Для удобной загрузки файлов рекомендуется компонент **SFTP server**. -6. Минимум 41693 КБ свободно в `/opt`; практический минимум — 50 МБ, рекомендуется 80 МБ. -7. Минимум 64 МБ свободно в `/tmp`; рекомендуется 128 МБ. +## Стандартное обновление -## Стандартное обновление через WebUI - -Основной и обязательный пользовательский путь обновления: +Публичные стабильные обновления устанавливаются только через WebUI: ```text BROray → Проверить обновление → Установить обновление ``` -Версия 2.2.5 загружается по точному полю `Filename` из OPKG-индекса, с запретом HTTP-кэша, уникальным параметром запроса и обязательной проверкой SHA-256. Административные скрипты установки и safe-upgrade остаются аварийными инструментами, но не заменяют проверку пользовательского пути WebUI. - -### Совместимость старого updater - -Переход с `2.1.1-2` полевым испытанием подтверждён, но старый updater потребовал отдельного совместимого ремонта до запуска установки: чтение `SHA256sum` из локального `src/gz` и значение `BRORAY_OPKG_LISTS_DIR` должны быть доступны также скопированному фоновому worker. Этот ремонт не устанавливает релиз; после него установка по-прежнему выполняется только через WebUI. - -В пакет 2.2.5 включён `preinst`-мост для обновления с ветки 2.1.1/2.2.0. Если старый updater уже успел создать копию в `/opt/broray/backup`, пакет переносит её в `/tmp`, очищает старые копии и мусор, создаёт после очистки новую актуальную копию в `/tmp` и только затем разрешает распаковку. Для этого `Installed-Size` используется как совместимый резерв OPKG, а фактический размер и обязательные 42000 КБ хранятся в отдельных проверяемых полях пакета. - -## Чистая установка - -После публикации релиза на `api.brovibe.cloud`: - -```sh -opkg update && -opkg install ca-bundle ca-certificates curl jq lighttpd lighttpd-mod-cgi openssl-util tar && -TARGET="/tmp/broray-install-2.2.5.sh" && -/opt/bin/curl -fL --retry 3 -o "$TARGET.part" \ - "https://api.brovibe.cloud/releases/broray-install-2.2.5.sh?v=$(date +%s)" && -echo "1b5d74a31c78556abd7341b100e7e961d3884c52b7e6b275724b7ed48e3a0ea2 $TARGET.part" | sha256sum -c - && -mv "$TARGET.part" "$TARGET" && -chmod 700 "$TARGET" && -/opt/bin/ash "$TARGET" -``` - -## Аварийное административное обновление - -Обычные обновления выполняются только через WebUI. Следующий скрипт предназначен для восстановления или диагностики, когда WebUI недоступен. - -```sh -opkg update && -opkg install ca-bundle ca-certificates curl jq lighttpd lighttpd-mod-cgi openssl-util tar && -TARGET="/tmp/broray-safe-upgrade-2.2.5.sh" && -/opt/bin/curl -fL --retry 3 -o "$TARGET.part" \ - "https://api.brovibe.cloud/releases/broray-safe-upgrade-2.2.5.sh?v=$(date +%s)" && -echo "dc2f417c40c47d50aa4e9ad29eaf6ea993e5b5e125f91b12a99ac4d75379417d $TARGET.part" | sha256sum -c - && -mv "$TARGET.part" "$TARGET" && -chmod 700 "$TARGET" && -BRORAY_TMP_ROOT=/tmp /opt/bin/ash "$TARGET" -``` - -IPK: - -```text -Файл: broray_2.2.5_aarch64-3.10.ipk -Размер: 13 995 075 байт -SHA-256: -8a2255e2c181a5f88438673c186da4f89870cb54bc01e656d57671d46cae9adc -``` - -## Документация - -- [Полевое подтверждение релиза 2.2.5](docs/FIELD-TEST-2.2.5.md) -- [Обязательные требования к релизам](docs/RELEASE-REQUIREMENTS.md) -- [Требования и совместимость](docs/REQUIREMENTS.md) -- [Установка, обновление и удаление](docs/INSTALLATION.md) -- [Полный справочник WebUI](docs/WEBUI.md) -- [Архитектура и безопасность](docs/ARCHITECTURE.md) -- [Примечания к релизу](docs/RELEASE-2.2.5.md) - -## WebUI - -После установки локальный адрес обычно имеет вид: - -```text -http://192.168.1.1:8080/ -``` - -Фактический LAN-адрес определяется автоматически. WebUI также может публиковаться через штатный KeenDNS HTTP Proxy, если он настроен на роутере. - -## CLI - -```sh -broray help -broray status -broray current -broray list -broray test -broray restart -broray xray update-check -broray xray update -broray-servers summary -broray-subscriptions list -broray-routes summary -broray-routes-dot status -``` +Release candidate 2.2.6 нельзя устанавливать из публичного канала до завершения полевого теста. ## Поддержка @@ -149,15 +65,4 @@ broray-routes-dot status ## Лицензия -Исходный код BROray распространяется по GNU GPL v3. Xray-core поставляется как отдельный сторонний компонент на собственных условиях; его лицензия находится в `third_party/xray/` и в установленном каталоге лицензий. - -## Нумерация версий - -- **BROray 2.2.5** — версия приложения, которую видит пользователь и которая используется как публичная версия OPKG. -- **WebUI-2.2.0-r3** — отдельная понятная версия WebUI. -- Техническая ревизия пакета хранится в поле `X-BROray-Package-Revision` и не подменяет версию приложения в интерфейсе. -- Поле «Доступная версия» показывает только `2.2.5`; технические сведения OPKG находятся отдельно. - -## Состояние исходного дерева GitHub - -Этот документ публикует сведения о фактически опубликованном и установленном пакете 2.2.5. Перенос точного исходного overlay релиза в дерево `root/`, синхронизация `web-src`/`web-new` и создание тега выполняются отдельным кодовым изменением; до него документация не означает побайтовое совпадение текущего `main` с публичным IPK. +BROray распространяется по GNU GPL v3. Xray-core поставляется как отдельный сторонний компонент на собственных условиях. diff --git a/docs/FIELD-TEST-2.2.6.md b/docs/FIELD-TEST-2.2.6.md new file mode 100644 index 0000000..7c29ec2 --- /dev/null +++ b/docs/FIELD-TEST-2.2.6.md @@ -0,0 +1,53 @@ +# Полевой тест BROray 2.2.6 + +## Идентичность кандидата + +Перед тестом зафиксировать: + +- имя архива кандидата и SHA-256; +- имя IPK, размер и SHA-256; +- SHA-256 safe-upgrade, installer и compatibility repair; +- WebUI `WebUI-2.2.0-r4`; +- исходную версию роутера и модель устройства. + +## Обязательные сценарии + +### A. Обновление 2.2.0-2 через WebUI + +- проверить доступное обновление; +- нажать «Установить обновление»; +- убедиться, что используется staging `Filename` и точная SHA-256; +- проверить пять служб, WebUI, Xray, ProxyN, DNS-over-TLS и маршруты; +- сравнить пользовательские серверы, подписки, активный сервер и настройки до/после. + +### B. Остановленная S28 + +- до запуска обновления остановить `S28broray-subscriptions`; +- убедиться, что создание копии завершается успешно; +- после установки проверить ожидаемое состояние всех служб и отсутствие ложной ошибки backup. + +### C. Принудительная ошибка и откат + +- вызвать контролируемую ошибку до завершения установки; +- проверить показ хвоста полного OPKG/preinst/postinst-журнала; +- подтвердить восстановление версии, OPKG-метаданных, пяти служб, пользовательских данных, runtime и сохранённых резервных копий; +- убедиться, что при успешном откате временный workspace удалён. + +### D. Повтор после отката + +- повторить штатное обновление через WebUI; +- подтвердить успешную установку тех же байтов кандидата; +- убедиться, что остаточные marker-файлы не мешают backup. + +### E. Обновление 2.2.4 через WebUI + +- повторить сценарий A с текущей стабильной версии 2.2.4. + +### F. Чистая установка + +- выполнить чистую установку кандидата на физическом поддерживаемом устройстве; +- проверить пять служб, WebUI, Xray, ProxyN, DNS-over-TLS, маршруты и отсутствие пользовательских/runtime-данных в исходном пакете. + +## Итоговый критерий + +Статус `PASS` разрешён только когда все сценарии A–F завершены теми же SHA-256. Любое изменение байтов отменяет результаты теста и требует нового кандидата. diff --git a/docs/RELEASE-2.2.6-ERROR-REGISTER.md b/docs/RELEASE-2.2.6-ERROR-REGISTER.md new file mode 100644 index 0000000..e0a81e2 --- /dev/null +++ b/docs/RELEASE-2.2.6-ERROR-REGISTER.md @@ -0,0 +1,234 @@ +# BROray 2.2.6 — реестр ошибок и обязательных защит + +Этот документ является блокирующим реестром релиза BROray 2.2.6. Он фиксирует обнаруженные дефекты, причины отклонения кандидатов и проверки, которые обязаны предотвращать повторение тех же ошибок. + +## Подтверждённое безопасное состояние + +- стабильный публичный канал: BROray `2.2.4`, WebUI `WebUI-2.2.0-r2`; +- SHA-256 stable `Packages`: `8e37d0f02825056fe96b267548cfc09836f911d1bf9c7d0b735ebdc6576256ea`; +- SHA-256 stable `Packages.gz`: `083521021e13975c2d63959ca6678a5d0fca6bf1eb9fe46eefda1bb3827067da`; +- тестовый роутер после очистки: BROray/OPKG `2.2.5`, Xray config OK, WebUI HTTP 200, один процесс S28; +- обязательный production source r10: `/root/BROray-2.2.6-candidate-r10/broray_2.2.6_aarch64-3.10.ipk`; +- SHA-256 production source r10: `c0bc9a8d0c17afe4987989a24ab03ed906e0c4acb5169a5216334e6548b3f9e2`; +- размер production source r10: `13997155` байт. + +Ни один кандидат не может менять stable до отдельного решения о продвижении уже проверенных неизменяемых байтов. + +## Хронология отклонённых кандидатов + +### r4 — разрушительная переустановка той же версии + +Симптом: после WebUI-переустановки OPKG оставался зарегистрирован как 2.2.6, но программный payload, Xray и службы исчезали. + +Причина: `opkg --force-reinstall` возвращал ненулевой код из-за предупреждений conffile; worker воспринимал это как провал, запускал второй reinstall как откат и не восстанавливал полный snapshot. + +Обязательная защита: + +- same-version reinstall не должен полагаться на повторный `opkg --force-reinstall`; +- старое дерево сохраняется до полной проверки нового payload; +- forced failure после переименования старого дерева обязан вернуть payload и службы. + +### r6–r8 — прогресс, DOM и неполная диагностика + +Обнаружены зависание прогресса, некорректное расположение карточки, ошибочная трактовка пути резервной копии как поля `error` и неполная проверка результата. + +Обязательная защита: + +- успешная операция завершается `state=success`, `stage=complete`, `progress=100`, `running=false`, пустым `error`; +- WebUI продолжает polling после временного исчезновения backend; +- информационные сообщения не записываются в `error`; +- DOM-якоря проверяются на фактической структуре страницы. + +### r8–r9 — несколько процессов S28 + +Симптом: init-скрипт сообщал `stopped`, хотя несколько процессов scheduler продолжали работать; ручной start создавал ещё один процесс. + +Обязательная защита: + +- S28 должен обнаруживать все процессы по точной командной строке; +- stop удаляет все старые процессы и PID-файлы; +- start/restart оставляет ровно один процесс; +- PID-файл обязан соответствовать единственному живому процессу; +- проверка выполняется сразу, через 10 и через 30 секунд. + +### r9 — полный архив в `/tmp` + +Симптом: транзакция остановилась при создании полного снимка в `/tmp`. + +Причина: `/tmp` является tmpfs/RAM; одновременно хранились пакет, распаковка и архив. + +Обязательная защита: + +- полный payload и полный резервный архив не создаются в `/tmp`; +- обязательный rollback использует атомарно переименованное старое дерево на том же filesystem; +- `/tmp` хранит только небольшие служебные файлы. + +### r10 — зависимость от IPK исходной версии + +Симптом: обновление с 2.2.5 остановилось, потому что staging не содержал точный IPK 2.2.5 для возврата. + +Причина: compatibility repair был привязан к набору прежних пакетов. + +Обязательная защита: + +- исходная версия определяется динамически через OPKG; +- allowlist исходных версий запрещён; +- previous-version IPK не требуется; +- rollback сохраняет локальное дерево, OPKG status/info, внешние пакетные файлы и состояние служб. + +### r11 — потеря unmanaged-файлов + +Симптом: success-path восстанавливал только фиксированный перечень `config`, `data`, `subscriptions`, `servers`, `routes`. + +Риск: могли исчезнуть `backup`, `logs`, `quality` и будущие пользовательские каталоги. + +Обязательная защита: + +- пользовательские данные определяются как все непакетные файлы и conffiles, а не фиксированный список каталогов; +- неизвестные будущие каталоги сохраняются; +- старые программные файлы не накладываются поверх нового payload; +- конфликт пользовательского пути с новым пакетным путём блокирует транзакцию до изменений. + +### r11 — права staging + +Симптом: локальная публикация прошла, публичный URL возвращал 404. + +Причина: каталоги staging получили mode 0700 при `umask 077`; nginx не мог пройти по дереву. + +Обязательная защита: + +- publisher принудительно устанавливает каталогам 0755, файлам 0644, владельца `root:root`; +- после локальной проверки обязательна внешняя HTTP-загрузка каждого файла и сравнение SHA-256. + +### r12 — валидатор проверял несуществующий путь + +Симптом: кандидат отклонён проверкой `preinst`, хотя валидатор искал его вне распакованного IPK. + +Обязательная защита: + +- независимый валидатор распаковывает итоговый IPK; +- проверяет реальные `control`, `preinst`, `postinst`; +- шаблоны и экспортированные standalone-файлы не заменяют проверку пакетных байтов. + +### r13 — тестовая модель не соответствовала release-среде + +Симптом: exact-preinst модель выбрала неподходящий `/opt/bin/tar` на release-сервере. + +Обязательная защита: + +- тестовый tar задаётся явно; +- runtime Keenetic выбирает проверенный `/opt/bin/tar` с безопасным fallback; +- exact-preinst исполняется на финальном пакете в изолированном PATH. + +### r14 — общий порог места для keep/skip + +Симптом: `keep` и `skip` блокировались одним порогом 42000 КБ. + +Обязательная защита: + +- место обязательной транзакции рассчитывается отдельно; +- дополнительное место постоянной копии `keep` рассчитывается отдельно; +- `skip` не запускает оценку persistent backup; +- если не помещается только `keep`, пользователь получает предложение перейти на `skip`; +- если не помещается транзакция, сообщается, что `skip` не поможет. + +### r14 — старый мусор и разросшийся access.log + +Фактический `access.log` вырос до `121594840` байт и занял существенную часть внутреннего накопителя. + +Обязательная защита: + +- до измерения места удаляются только подтверждённые завершённые временные транзакции, `.part`, `.tmp`, временные IPK и OPKG-кэш; +- активный snapshot и аварийные деревья защищены; +- постоянные пользовательские архивы автоматически не удаляются; +- технический `access.log` обнуляется только после превышения фиксированного безопасного лимита; +- после cleanup место измеряется повторно. + +### r14 — зависимость оценщика от `stat` + +Симптом: ветка `keep` не смогла оценить размер дополнительной копии; конкретный путь не сообщался. + +Обязательная защита: + +- обычные файлы измеряются через `wc -c`; +- ссылки — через `readlink` и `wc -c`; +- `stat` запрещён внутри portable size estimator; +- выполняются три попытки; +- исчезнувший или изменившийся файл возвращает точный `relative/path|reason`; +- модель исполняется в PATH без `stat`. + +### r14 — неполный возврат compatibility overlay после preflight-stop + +После безопасной остановки требовалась ручная очистка и проверка восстановленных файлов. + +Обязательная защита: + +- каждый отказ до snapshot синхронно восстанавливает backend, WebUI JS, CGI, system wrapper и исходный feed; +- marker и временный compatibility snapshot удаляются только после проверки восстановления; +- cache OPKG инвалидируется после возврата feed; +- ошибка restore не скрывается исходной ошибкой preflight. + +### r15 — mock-only PASS и неинициализированный runtime + +Симптом production-сборки: + +```text +ash: can't create .../base/run/broray/update.json: nonexistent directory +``` + +Причина: mock-IPK сохранял тестовый путь cache, а production backend после source переопределял его под `$BRORAY_BASE/run/broray/update.json`; модель не создала каталог после инициализации настоящего backend. + +Обязательная защита: + +- mock-тест не является production-доказательством; +- все runtime-пути создаются и проверяются после source настоящего production backend; +- модели исполняются на backend, извлечённом из exact production source; +- stdout/stderr неуспешной ветки сохраняются; +- первый отсутствующий путь выводится явно. + +## Дополнительные инварианты безопасности + +### Пути и архивы + +- абсолютные пути и `..` запрещены; +- управляющие символы в путях запрещены; +- имена с начальным `-` обрабатываются безопасно; +- небезопасные symlink targets блокируются до mutation; +- metadata persistent backup (`.broray-user-backup-v3`, `manifest.json`) не могут пересекаться с пользовательскими путями; +- дублированные и неканонические члены архива запрещены; +- metadata обязана быть обычными файлами, не symlink. + +### OPKG и feed + +- прямой `opkg upgrade broray` без валидного локального snapshot блокируется `preinst`; +- сохранённая sourceVersion сверяется с OPKG registration, но не сравнивается с allowlist; +- исходный feed может быть обычным файлом, отсутствовать или быть symlink; +- восстановление feed атомарное и проверяемое; +- staging содержит одну запись BROray и один IPK кандидата. + +### Резервные копии + +- обязательный транзакционный rollback всегда включён; +- persistent backup — отдельный выбор `keep`/`skip`; +- `keep` включён по умолчанию и рекомендован для USB/достаточного накопителя; +- `skip` не отключает автоматический rollback; +- пользовательские постоянные архивы не удаляются без явного выбора; +- `last-backup` сохраняется только если указывает на реально существующий валидный архив. + +## Полные release gates + +Перед передачей следующего production-кандидата обязательны: + +1. точный source r10 с утверждёнными SHA-256 и размером; +2. три чистые production-сборки A/B/C в `env -i` и независимых каталогах; +3. побайтовое совпадение деревьев, IPK, архивов, `Packages`, `Packages.gz` и всех helper-файлов; +4. независимый валидатор, не использующий логику builder как источник истины; +5. финальная холодная распаковка копии результата в другом parent-каталоге; +6. негативные mutation controls для top-level, staging, symlink, duplicate archive member и специальных mode bits; +7. `bash -n`, BusyBox `ash -n`, `node --check`, JSON, tar/gzip и реальный IPK control/preinst/postinst; +8. модели keep, skip, transaction-insufficient, keep-only-insufficient, no-stat, disappearing/changing file, internal storage, USB, forced rollback, feed restore и S28 singleton; +9. подтверждение неизменности stable и защищённого staging; +10. отдельная staging-публикация и только затем физическая матрица Keenetic; +11. stable promotion только тех же неизменяемых байтов после полного field-test PASS. + +Любой FAIL отклоняет байты. Исправление требует нового кандидата и повторения всего цикла с нуля. \ No newline at end of file diff --git a/docs/RELEASE-2.2.6.md b/docs/RELEASE-2.2.6.md new file mode 100644 index 0000000..ee4de46 --- /dev/null +++ b/docs/RELEASE-2.2.6.md @@ -0,0 +1,52 @@ +# BROray 2.2.6 — release candidate + +## Статус + +BROray 2.2.6 подготовлен как **неизменяемый release candidate**, а не как уже опубликованный стабильный релиз. Текущий публичный стабильный канал остаётся на BROray/OPKG 2.2.4. + +Публичное продвижение 2.2.6 разрешено только после физического теста тех же байтов через WebUI и итогового отчёта `PASS`. + +Кандидаты `r1`, `r2` и `r3` не являются допустимыми для полевого теста: + +- `r1` не завершил независимую распаковку IPK; +- `r2` не смог устойчиво преобразовать реальный блок `opkg install`; +- `r3` собрал и опубликовал staging, но внешний compatibility repair сохранил старый ожидаемый SHA пакета и поэтому отклонил бы правильный IPK 2.2.6. + +Текущий кандидат — **r4**. Он встраивает в compatibility repair точные `SHA256sum` и `Filename` собранного IPK и повторно проверяет эти значения до упаковки. + +## Причины выпуска + +BROray 2.2.5 был отозван после реального теста на роутере с версией `2.2.0-2`: + +1. updater передавал резервную копию полного `/opt` с путями `broray/...`, а пакетный `preinst` принимал только rootless-пути `bin/`, `lib/`, `web-new/`, `config/`; +2. функция записи состояния служб не имела явного успешного возврата и могла завершиться кодом остановленной последней службы; +3. пользователю показывалась общая ошибка OPKG без полезного хвоста `preinst`/`postinst`; +4. серверная публикация первоначально выдала `.sh` с правами `0700`, из-за чего Nginx отвечал `403`. + +## Исправления + +- два явных допустимых формата backup; +- `return 0` после успешного учёта служб; +- `BRORAY_OPKG_CLEANUP_DONE=1` при передаче уже проверенной копии; +- полный журнал OPKG до отката; +- staging-публикация с внешней HTTP/SHA-проверкой; +- права публичных статических файлов `0644`; +- compatibility repair содержит точные SHA-256 и Filename candidate IPK; +- правила релиза 1.3 и запрет пересборки после field test. + +## Порядок выпуска + +1. На сервере собрать кандидат builder r4 из точных файлов отозванного 2.2.5 в карантине. +2. Сверить внутренний `SHA256SUMS` и внешний SHA архива кандидата. +3. Опубликовать кандидат только в `/releases/staging/broray/2.2.6-r4/`. +4. Подготовить тестовый роутер к staging и запустить установку исключительно из WebUI. +5. Выполнить матрицу из [`FIELD-TEST-2.2.6.md`](FIELD-TEST-2.2.6.md). +6. После `PASS` продвинуть точные байты без пересборки; затем обновить документацию, GitHub tag и release notes. + +## Что не считается выпуском + +- лабораторная распаковка IPK; +- успешный `bash -n`/`ash -n`; +- локальная симуляция публикации; +- ручной `opkg install` вместо WebUI; +- установка пересобранного после field test пакета. diff --git a/docs/RELEASE-REQUIREMENTS.md b/docs/RELEASE-REQUIREMENTS.md index b4fc5b7..73ab708 100644 --- a/docs/RELEASE-REQUIREMENTS.md +++ b/docs/RELEASE-REQUIREMENTS.md @@ -1,39 +1,45 @@ # Обязательные требования к релизам BROray -Версия документа: 1.2, принята для BROray 2.2.5. +Версия документа: 1.3, принята для BROray 2.2.6. ## Неподлежащий изменению порядок обновления -1. Все публичные обновления проверяются полным пользовательским путём: `BROray → Проверить обновление → Установить обновление`. -2. До загрузки пакета обновления и до создания новой копии updater удаляет все старые автоматические резервные копии BROray из `/opt/broray/backup`, `/opt/broray/backups` и `/opt/broray/routes/backup`. -3. Затем полностью удаляются управляемые временные данные, старые релизные файлы BROray в `/opt/tmp` и OPKG-кэш. Только после завершения этой очистки разрешено создавать актуальную копию. Серверы, подписки, активная конфигурация Xray, настройки и установленные маршруты не удаляются. +1. Финальный публичный релиз запрещено собирать заново после полевого теста. Сначала создаётся неизменяемый release candidate, затем именно эти байты проходят полевой тест и только после этого побайтово продвигаются в публичный канал. +2. Все публичные обновления проверяются полным пользовательским путём: `BROray → Проверить обновление → Установить обновление`. +3. До загрузки нового IPK и до создания новой копии updater удаляет старые автоматические резервные копии BROray, управляемые временные данные и OPKG-кэш. Серверы, подписки, активная конфигурация Xray, настройки, пользовательские маршруты и установленные наборы маршрутов не удаляются. 4. После очистки повторно измеряется свободное место в `/opt` и `/tmp`. -5. Создаётся ровно одна актуальная полная резервная копия в `/tmp/broray-update-/backup.tar.gz`. Она обязательно проверяется чтением архива и наличием обязательных разделов. Только после успешной проверки этой копии разрешены загрузка точного нового IPK, подготовка пакета возврата и установка. -6. До `opkg install` свободное место в `/opt` должно быть не меньше значения `X-BROray-Required-Opt-KB` (для 2.2.5 — 42000 КБ). При недостатке места установка не запускается, а WebUI показывает доступный и требуемый объём. -7. Временная копия никогда не переносится в `/opt` перед установкой и не уменьшает место раздела OPKG. -8. При ошибке используется точный пакет предыдущей установленной версии и актуальная копия из `/tmp`. При успешном откате временный каталог удаляется; при неудачном откате он сохраняется для ручного восстановления. -9. После установки проверяются версия приложения и OPKG, пять служб, WebUI, Xray, ProxyN, DNS-over-TLS и обязательные backend-файлы маршрутов. -10. После успешной проверки временная копия и staging удаляются. -11. Чтение метаданных OPKG обязано работать как с обычным `Packages`, так и со сжатым локальным списком `src/gz`; отсутствие `SHA256sum` запрещено трактовать как несовпадение суммы. -12. Для каждой поддерживаемой старой версии проверяется реальный переход через её установленный WebUI. Если старый updater имеет известный дефект, публикуется отдельный минимальный совместимый ремонт updater, который не устанавливает релиз и после которого сама установка выполняется только через WebUI. -13. Если старый updater уже создал копию в `/opt`, `preinst` переносит её в `/tmp`, очищает старые копии и мусор, создаёт после очистки новую актуальную копию в `/tmp` и сохраняет совместимый путь отката до завершения проверки. -14. `Installed-Size` может использоваться как совместимый резерв только для входа старого OPKG в `preinst`; реальный размер и обязательное место фиксируются в `X-BROray-Actual-Installed-Size` и `X-BROray-Required-Opt-KB`. +5. Создаётся ровно одна актуальная полная резервная копия в `/tmp/broray-update-/backup.tar.gz`; она проверяется чтением архива и обязательными разделами до загрузки нового пакета. +6. Контракт резервной копии версионируется. Updater может передавать полную копию `/opt` с корнями `broray/`, `bin/` и `etc/`; пакетный `preinst` может создавать внутреннюю копию с корнями `bin/`, `lib/`, `web-new/`, `config/`. `preinst` обязан явно распознавать оба формата и запрещает смешанный или неполный формат. +7. Функции учёта состояния служб всегда завершаются явным `return 0`, если состояние успешно записано; остановленная необязательная служба не является ошибкой создания резервной копии. +8. До `opkg install` свободное место в `/opt` должно быть не меньше `X-BROray-Required-Opt-KB`. Временная копия никогда не переносится в `/opt` перед установкой. +9. При ошибке используется точный пакет предыдущей версии и актуальная копия из `/tmp`. Успешный откат восстанавливает код, OPKG-метаданные, пользовательские данные, журналы, runtime-состояние и ранее сохранённые резервные копии. +10. Полный вывод `opkg install`, `preinst` и `postinst` сохраняется в журнале и последние строки выводятся пользователю при ошибке до запуска отката. +11. После установки проверяются приложение и OPKG, пять служб, WebUI, Xray, ProxyN, DNS-over-TLS, маршруты и сохранность пользовательских данных. +12. После успешной проверки временная копия и staging удаляются. +13. Чтение метаданных OPKG работает с `Packages` и сжатым локальным `src/gz`; отсутствие прочитанного `SHA256sum` является ошибкой метаданных, а не сообщением о несовпадении суммы. +14. Для каждой поддерживаемой старой версии проверяется реальный переход через установленный WebUI. Известный дефект старого updater исправляется отдельным минимальным совместимым ремонтом, который сам релиз не устанавливает. +15. Публичные `.sh` и `.txt` устанавливаются с правами не строже `0644`; публикация обязана проверять HTTP 200 и SHA-256 каждого файла от имени внешнего клиента. -## Релизные запреты +## Обязательная матрица перед публичным выпуском -- Нельзя изменять уже опубликованный IPK под прежним именем или версией. -- Нельзя публиковать `Packages` раньше самого IPK. -- Нельзя считать релиз готовым только по статическим тестам: обязателен реальный путь WebUI на поддерживаемом Keenetic/Netcraze. -- Нельзя выполнять релизную установку на тестовом роутере ручным `opkg install`, локальным IPK или runner-скриптом вместо WebUI. -- Нельзя создавать временную резервную копию обновления в `/opt`. +- две детерминированные сборки кандидата побайтово совпадают; +- статические проверки BusyBox `ash`, JavaScript и JSON; +- динамический тест обоих форматов резервной копии; +- обновление через WebUI с 2.2.0-2 и актуальной стабильной 2.2.4; +- чистая установка на физическом роутере; +- остановленная S28 до обновления не ломает создание копии; +- принудительная ошибка `preinst` и автоматический откат; +- повторное обновление после успешного отката; +- сохранность серверов, подписок, активного сервера, маршрутов, DNS и ProxyN; +- публичные обычная и no-cache загрузки совпадают с `Packages`; +- документация переключается на новую версию только после успешного полевого отчёта; +- публикационный архив и detached-команда выдаются вместе и имеют отдельные SHA-256. -## Обязательные доказательства перед финальным статусом +## Релизные запреты -- две детерминированные сборки IPK побайтово совпадают; -- SHA-256 публичного IPK совпадает с `Packages` при обычной и no-cache загрузке; -- BusyBox `ash` принимает все shell-скрипты; -- updater удаляет старые копии до создания новой; -- актуальная копия расположена только в `/tmp`; -- тест недостатка места останавливает операцию до `opkg install`; -- тест ошибки установки подтверждает автоматический откат; -- сохранность пользовательских данных подтверждена сравнением до и после. +- Нельзя изменять опубликованный файл под прежним именем. +- Нельзя публиковать `Packages` раньше IPK и установочных файлов. +- Нельзя объявлять полевой успех по лабораторной симуляции. +- Нельзя публиковать release candidate как стабильный до физического WebUI-теста. +- Нельзя скрывать вывод OPKG общей фразой без сохранённого журнала. +- Нельзя оставлять отозванный пакет, установщик, updater или документацию в публичном канале. diff --git a/scripts/run-release-candidate-builder-2.2.6.sh b/scripts/run-release-candidate-builder-2.2.6.sh new file mode 100644 index 0000000..14028b4 --- /dev/null +++ b/scripts/run-release-candidate-builder-2.2.6.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -Eeuo pipefail +umask 077 +export LC_ALL=C + +CONTROLLER="/root/BROray-2.2.6-full-control-production-r41.sh" +EXPECTED_CONTROLLER_SHA="1807bd06eb7e5dd329d65dab2fcba5209f08989b00289a27c0eedbf01aff6921" +EXPECTED_CONTROLLER_SIZE="424919" + +SOURCE_IPK="/root/BROray-2.2.6-candidate-r10/broray_2.2.6_aarch64-3.10.ipk" +EXPECTED_SOURCE_SHA="c0bc9a8d0c17afe4987989a24ab03ed906e0c4acb5169a5216334e6548b3f9e2" +EXPECTED_SOURCE_SIZE="13997155" + +STABLE_PACKAGES="/var/www/api.brovibe.cloud/releases/opkg/aarch64-3.10/Packages" +STABLE_PACKAGES_GZ="${STABLE_PACKAGES}.gz" +EXPECTED_STABLE_SHA="8e37d0f02825056fe96b267548cfc09836f911d1bf9c7d0b735ebdc6576256ea" +EXPECTED_STABLE_GZ_SHA="083521021e13975c2d63959ca6678a5d0fca6bf1eb9fe46eefda1bb3827067da" + +fail() { + printf '\nОШИБКА: %s\n' "$*" >&2 + printf 'Stable и staging не изменялись этой командой.\n' >&2 + exit 1 +} + +sha_of() { + sha256sum "$1" | awk '{print $1}' +} + +size_of() { + wc -c <"$1" | tr -d ' ' +} + +printf '%s\n' "==================================================" +printf '%s\n' "BROray 2.2.6 — exact production full-control r41" +printf '%s\n' "==================================================" + +[ "$(id -u)" -eq 0 ] || fail "требуется root" + +for command_name in bash busybox node python3 tar gzip sha256sum awk find sort stat cmp jq env wc tr; do + command -v "$command_name" >/dev/null 2>&1 || fail "не найдена команда $command_name" +done + +[ -s "$CONTROLLER" ] || fail "контроллер отсутствует: $CONTROLLER" +[ "$(sha_of "$CONTROLLER")" = "$EXPECTED_CONTROLLER_SHA" ] || fail "SHA-256 контроллера не совпадает" +[ "$(size_of "$CONTROLLER")" = "$EXPECTED_CONTROLLER_SIZE" ] || fail "размер контроллера не совпадает" +bash -n "$CONTROLLER" || fail "контроллер не прошёл bash -n" + +[ -s "$SOURCE_IPK" ] || fail "точный production source r10 отсутствует" +[ "$(sha_of "$SOURCE_IPK")" = "$EXPECTED_SOURCE_SHA" ] || fail "SHA-256 production source r10 не совпадает" +[ "$(size_of "$SOURCE_IPK")" = "$EXPECTED_SOURCE_SIZE" ] || fail "размер production source r10 не совпадает" +tar -tzf "$SOURCE_IPK" >/dev/null 2>&1 || fail "production source r10 не читается" + +[ -s "$STABLE_PACKAGES" ] || fail "stable Packages отсутствует" +[ -s "$STABLE_PACKAGES_GZ" ] || fail "stable Packages.gz отсутствует" +[ "$(sha_of "$STABLE_PACKAGES")" = "$EXPECTED_STABLE_SHA" ] || fail "stable Packages изменён" +[ "$(sha_of "$STABLE_PACKAGES_GZ")" = "$EXPECTED_STABLE_GZ_SHA" ] || fail "stable Packages.gz изменён" +gzip -cd "$STABLE_PACKAGES_GZ" | cmp - "$STABLE_PACKAGES" >/dev/null || fail "stable Packages.gz не соответствует Packages" + +for forbidden in \ + BRORAY_FULL_CONTROL_TEST_MODE \ + BRORAY_FULL_CONTROL_TEST_SOURCE_IPK \ + BRORAY_FULL_CONTROL_TEST_SOURCE_SHA \ + BRORAY_FULL_CONTROL_TEST_SOURCE_SIZE \ + BRORAY_BUILDER_TEST_MODE \ + BRORAY_BUILDER_TEST_SOURCE_IPK \ + BRORAY_BUILDER_TEST_SOURCE_SHA \ + BRORAY_BUILDER_TEST_SOURCE_SIZE \ + BRORAY_TAR_BIN \ + BRORAY_OPT_ROOT \ + BRORAY_TMP_ROOT \ + BRORAY_LOCAL_ROLLBACK_TREE \ + BRORAY_LOCAL_ROLLBACK_META +do + eval "value=\${$forbidden:-}" + [ -z "$value" ] || fail "запрещена переменная окружения $forbidden" +done + +bash "$CONTROLLER" +result=$? + +printf '\nКод завершения: %s\n' "$result" +printf '%s\n' "Контроллер выполняет три чистые exact-production сборки A/B/C, независимый валидатор, финальную холодную проверку, негативные controls и контроль неизменности stable/staging." +printf '%s\n' "Контроллер не публикует staging и не изменяет stable." +printf '%s\n' "Только итог BROray 2.2.6-r41 FULL CONTROL: PASS разрешает следующий отдельный этап staging." +printf '%s\n' "==================================================" +exit "$result"