Живое тестирование shater v0.2.6 на mini_router
Дата: 2026-07-25
Устройство: Bananapi BPi-R3 Mini · ImmortalWrt 25.12-linkup · aarch64_cortex-a53
Установка: из подписанного apk-фида apk-v0.2.6-aarch64_cortex-a53
Пакеты: shaterd 0.2.0-r3, shater-core 0.2.0-r3, luci-app-shater 0.2.0-r2, byedpi 0.17.3-r1
Сборка: CI run 61, коммит 024e9308c (вершина main)
Сценарий: полное удаление предыдущей установки → чистая установка из фида →
проверка дефолтного состояния → восстановление рабочего конфига с подписками
(315 узлов) → функциональная проверка.
Итог: 79 проверок, 74 PASS, 5 находок (детали и разбор — в
shater-bugs-2026-07-25.md на рабочем столе).
1. Релиз и фид
| # |
Проверка |
Результат |
| T1 |
Публикация apk-v0.2.6-<arch> для обеих архитектур |
PASS |
| T2 |
Ассеты: 4 .apk + packages.adb + shater-apk.pem |
PASS |
| T3 |
apk update принимает индекс (проверка EC-подписи) |
PASS |
| T4 |
Пакеты видны в нужных версиях (r3/r3/r2) |
PASS |
| T5 |
Диагностика сборки: kmod packages selected (=m): 0 (было 1078) |
PASS |
| T6 |
Собраны ровно наши 4 пакета |
PASS |
| T7 |
opkg-лейн v0.2.6 (24.10) тоже зелёный |
PASS |
2. Установка
| # |
Проверка |
Результат |
| T8 |
apk add luci-app-shater byedpi — 4 пакета |
PASS |
| T9 |
Зависимости kmod-nft-tproxy/kmod-nft-socket из базового фида |
PASS |
| T10 |
Целостность: apk manifest = sha256 файла на диске |
PASS |
| T11 |
Установлен именно бинарь v0.2.6 (5 491 616 Б vs 5 488 336 Б в r2) |
PASS |
| T12 |
init-скрипты shater, shater-cron |
PASS |
| T13 |
sysctl.d/99-shater.conf, hotplug.d/iface/99-shater |
PASS |
| T14 |
boot-линки S99shater, K10shater, S96shater-cron |
PASS |
3. Дефолтное состояние (чистая установка)
| # |
Проверка |
Результат |
| T15 |
Дефолтный конфиг создан uci-defaults (27 строк) |
PASS |
| T16 |
enabled='0' — плоскость не ставится без согласия |
PASS |
| T17 |
Заготовлен tproxy-inbound на LAN, пресеты выключены |
PASS |
| T18 |
Демон стартует, plane=none, table=false |
PASS |
| T19 |
Права конфига -rw------- (0600) |
PASS |
4. Восстановление рабочего конфига
| # |
Проверка |
Результат |
| T20 |
Восстановление из бэкапа (3213 UCI-строк) |
PASS |
| T21 |
Кэш подписок цел: 315 узлов в 4 файлах |
PASS |
| T22 |
shaterd migrate → ok, схема v1 |
PASS |
| T23 |
Старт с реальным конфигом: active, engine_running, plane=full |
PASS |
5. Data plane
| # |
Проверка |
Результат |
| T24 |
Таблица inet shater создана (9 цепочек/сетов) |
PASS |
| T25 |
16 tproxy-правил |
PASS |
| T26 |
ip rule from all fwmark 0x2000 lookup shater |
PASS |
| T27 |
accept_local=1 на br-lan |
PASS |
| T28 |
DNS-divert: dport 53 → tproxy :12345 для LAN-интерфейсов |
PASS |
| T29 |
DoT заблокирован: dport 853 reject |
PASS |
| T30 |
block_doh=1, правила присутствуют |
PASS |
| T31 |
Kill-switch fail-closed: цепочка forward завершается drop для LAN (v4+v6) |
PASS |
| T32 |
fw4 и dnsmasq не тронуты (свои таблицы целы) |
PASS |
6. Панель и API
| # |
Проверка |
Результат |
| T33 |
SPA отдаётся на :8088 |
PASS |
| T34 |
shaterd mint-token выдаёт одноразовый токен |
PASS |
| T35 |
/api/status без сессии → 401 |
PASS |
| T36 |
/api/session (POST, JSON) → 200 + cookie HttpOnly; SameSite=Strict; Max-Age=28800 |
PASS |
| T37 |
/api/status по cookie отдаёт данные, совпадающие с CLI |
PASS |
| T38 |
/api/config — 340 записей узлов |
PASS |
| T39 |
/api/groups/health — 103 протестировано, 13 живых, выбран FR-vless-8 |
PASS |
| T40 |
/api/devices — устройства с IPv4/IPv6/MAC |
PASS |
| T41 |
/api/interfaces — ewan/eth1 10.0.0.125/24 zone=wan |
PASS |
| T42 |
/api/ruleset/status — remote-ruleset обновлён сегодня |
PASS |
| T43 |
/api/stats — memory backend, счётчики и top-domains |
PASS |
| T44 |
/api/stats/log — query-log с доменом, qtype, rcode, сервером |
PASS |
| T45 |
/api/log?range=100 — пусто (следствие log_file='0', не дефект) |
OK |
7. Жизненный цикл конфигурации
| # |
Проверка |
Результат |
| T46 |
shaterd apply → {"changed":false}, can_rollback=true |
PASS |
| T47 |
shaterd confirm снимает авто-откат (can_rollback=false) |
PASS |
| T48 |
shaterd rollback после confirm корректно сообщает об отсутствии last-good |
PASS |
| T49 |
shaterd reconcile (SIGHUP) не роняет движок |
PASS |
| T50 |
shaterd sub update all-qomar — реально обновил 143 узла |
PASS |
| T51 |
shaterd blocklist update → reconcile signalled |
PASS |
| T52 |
shaterd schedule due → reconcile signalled |
PASS |
8. Устойчивость
| # |
Проверка |
Результат |
| T53 |
kill -9 демона → procd поднимает новый PID |
PASS |
| T54 |
После respawn: engine_running=true, plane=full |
PASS |
| T55 |
stop снимает таблицу inet shater полностью |
PASS |
| T56 |
stop → пауза → start: плоскость восстанавливается |
PASS |
| T57 |
Сеть при остановленном shater не деградирует |
PASS |
| T58 |
Память: 253 МБ занято из 2 ГБ при работающем движке |
PASS |
9. DNS
| # |
Проверка |
Результат |
| T59 |
Резолв через 127.0.0.1 |
PASS |
| T60 |
LAN-клиенты резолвят через движок (query-log растёт) |
PASS |
| T61 |
.lan-домены остаются за dnsmasq |
PASS |
| T62 |
dnsmasq жив и слушает на всех адресах |
PASS |
| T63 |
Резолв через LAN-адрес 10.67.0.1 после restart |
FAIL — B3 |
| T64 |
Тот же резолв после stop → пауза → start |
PASS |
10. Конфигурация и логи
| # |
Проверка |
Результат |
| T65 |
5 правил маршрутизации, 2 профиля, активен ethernet-uplink |
PASS |
| T66 |
Два правила default, оба catch-all — нижнее живое, верхнее мертво |
FAIL — B1 |
| T67 |
shaterd nodes всегда возвращает [] |
FAIL — B2 |
| T68 |
Логи уходят в syslog (log_syslog=1, 22 записи) |
PASS |
| T69 |
ANSI-escape коды в syslog |
FAIL — B5 |
| T70 |
loglevel=warning соблюдается |
PASS |
| T71–T79 |
Прочие проверки состояния (статус-поля, права, uptime, счётчики, целостность таблиц) |
PASS |
Находки
| ID |
Суть |
Важность |
| B1 |
Два catch-all правила default; одно из них не работает никогда. Поправка к первоначальному диагнозу: правило без условий задаёт route.Final, а не выпускается как match-all, поэтому выигрывает ПОСЛЕДНЕЕ (order=100 → group:auto) — трафик идёт через прокси, а мёртвая настройка это order=20 → direct |
средняя |
| B2 |
shaterd nodes — заглушка, всегда [], хотя usage обещает список узлов (в кэше 315, в /api/config 340) |
средняя |
| B3 |
После service shater restart резолв к LAN-адресу роутера не работает и не восстанавливается; stop+пауза+start — работает (гонка) |
средняя |
| B4 |
PKG_RELEASE не менялся с v0.2.1 → v0.2.2…v0.2.6 выходят как r3 при разном содержимом; apk upgrade не увидит обновления |
средняя |
| B5 |
ANSI-раскраска попадает в syslog |
низкая |
Разбор с воспроизведением — в shater-bugs-2026-07-25.md.
История CI по этому релизу
Путь до зелёной сборки apk-лейна занял четыре итерации, каждая вскрывала
следующий слой одной причины:
| Тег |
Что чинили |
Итог |
| v0.2.2 |
— (первый прогон с фиксами аудита) |
Disk quota exceeded, 3593 apk mkpkg kmod-* |
| v0.2.3 |
.config строится с нуля, а не дописывается |
1078 kmod — SDK вообще не везёт .config |
| v0.2.4 |
Выключены ALL/ALL_KMODS/ALL_NONSHARED |
1078 kmod — они выбираются не через ALL_KMODS |
| v0.2.5 |
Второй проход: явное is not set для каждого kmod |
1078 kmod — kconfig игнорирует user-значение у беспромптовых символов |
| v0.2.6 |
Удаление сгенерированных блоков config PACKAGE_* (default m) из Config-build.in |
0 kmod, сборка зелёная |
Корень: target/sdk/Makefile генерирует Config-build.in прогоном
convert-config.pl по конфигу бильдбота, где ALL_KMODS=y уже развернулся в
CONFIG_PACKAGE_kmod-*=m на каждый модуль. Фильтр next if /^(# )?CONFIG_PACKAGE/
в скрипте стоит в ветке else, куда строка со знаком = не попадает, поэтому
каждый kmod приезжает в SDK как безусловный default m.