fix(admin): закрыть обещания панели, которые продукт не выполнял
Девятый проход, по итогам приёмки v1.0.0-rc1 на живом Debian 13. Общая тема:
интерфейс обещал оператору то, что продукт умел, но до чего не доходило
управление.
Секрет пира. Подпись под полем предлагала оставить его пустым, сервер умел его
сгенерировать, и генерация была недостижима: в go-playground/validator тег
omitempty НЕ пропускает правило, если поле объявлено указателем и указатель не
nil — hasValue считает указатель на пустую строку «значением». Правило min=6
применялось к пустой строке и отказывало. Ловушка закрыта общим шагом
нормализации DTO, а не тегом на одном поле: та же ловушка ломала фильтр списка
пиров, где очищенный крестиком el-input отправляет `?name=`. Граница проходит по
каждому полю отдельно — у remark пустая строка означает «убрать пометку», у
disabled ноль означает «включён».
Отказы. Любая ошибка любого поля превращалась в слово `invalid`, а слой vo
определял код ответа СРАВНЕНИЕМ текста сообщения — тот же антипаттерн, который
запрещён панели, только на сервере. Ответ несёт errors[{code, field, message,
params}]; панель выбирает фразу по коду и подставляет причины под поля.
Сессия. Ветка «войдите заново» была недостижима дважды: сервер отвечает HTTP 200
на любой отказ, поэтому обработчик ошибок axios не вызывался, а условие в нём
проверяло code === "A0230" и поле msg, которых в этом API никогда не было.
Истёкший токен вдобавок уезжал с кодом системной ошибки.
Иконки. Контракт currentColor был объявлен в двух местах и не действовал: восемь
ассетов несли литеральный fill="#000000" на <path>, а атрибут представления
перебивает унаследованное CSS-свойство. Под это попадали все семь иконок
бокового меню на фоне #181818.
Имя пира. Два правила на одном поле противоречили друг другу (min=1 против
6-32), а копия набора символов в слое контроллеров несла неэкранированный дефис
и впускала `, - . / : ; <` — через панель проходило имя peer/name, которое
импорт того же пира отклонял. Набор символов ЛОГИНА сознательно не сужен и
закреплён тестом: он приходит из HY2XS_ADMIN_USER и оркестратором не
ограничивается.
Добавлены подпись «Разработано во Flamy» с адресом, принадлежащим приложению, и
контрактные тесты панели как обязательный шаг сборки. Их исполняет Bun, а не
vitest: jsdom не вычисляет currentColor и визуальной корректности не доказал бы,
зато vitest привёл бы в граф pnpm audit сотню транзитивных зависимостей.
docs/ разложена по слоям, 11-testing-and-acceptance.md (117 КБ) разбит на пять
частей, добавлен docs/acceptance/ с отчётом о прогоне rc1 и перечнем дефектов.
Обход документации в приёмке стал рекурсивным: плоский docs/*.md после
разнесения по каталогам совпадал бы ровно с одним файлом.
This commit is contained in:
@@ -515,7 +515,7 @@ HY2XS_UI_PUBLIC_ACCESS=false
|
||||
Если PHASE 0 не прошла, установщик завершается с ошибкой и **сервер остаётся в
|
||||
том же состоянии, в котором был**. HY2XS v1 не устанавливается поверх
|
||||
предыдущего поколения и не мигрирует его состояние: очистка старой установки —
|
||||
отдельная явная операция, см. [docs/14-legacy-cleanup.md](docs/14-legacy-cleanup.md).
|
||||
отдельная явная операция, см. [docs/operations/14-legacy-cleanup.md](docs/operations/14-legacy-cleanup.md).
|
||||
|
||||
### 10. Получите bootstrap‑пароль админки
|
||||
|
||||
@@ -818,7 +818,7 @@ HY2XS v1 не поддерживает установку поверх и не
|
||||
Что делать:
|
||||
|
||||
1. сохраните нужные данные (база пиров, конфиг) — см.
|
||||
[docs/14-legacy-cleanup.md](docs/14-legacy-cleanup.md);
|
||||
[docs/operations/14-legacy-cleanup.md](docs/operations/14-legacy-cleanup.md);
|
||||
2. посмотрите план очистки: `sudo ./purge-v0.sh`;
|
||||
3. выполните очистку: `sudo ./purge-v0.sh --apply --yes-i-know`;
|
||||
4. повторите установку.
|
||||
@@ -997,22 +997,25 @@ export GITHUB_TOKEN=<token>
|
||||
|
||||
1. проверяет контракт `versions.env` (`verify_versions_contract`);
|
||||
2. прогоняет тесты и типы оркестратора (`bun test`, `tsc --noEmit`);
|
||||
3. определяет последнюю стабильную версию Hysteria, берёт ожидаемый SHA‑256 из upstream `hashes.txt` и сверяет с ним скачанный артефакт;
|
||||
4. проходит compatibility gate: реальный бинарник Hysteria должен принять канонический конфиг HY2XS для Gecko и для Salamander;
|
||||
5. собирает orchestrator, frontend и backend, проставляя версию админки из контракта;
|
||||
6. прогоняет `go vet` и `go test` для HY2XS admin;
|
||||
7. проверяет граф зависимостей на известные уязвимости (`govulncheck ./...` и `pnpm audit` по всему lock‑графу);
|
||||
8. формирует архив и прогоняет acceptance‑проверки.
|
||||
3. прогоняет контрактные тесты панели (спрайт иконок, словари локализации, коды ошибок, атрибуция);
|
||||
4. определяет последнюю стабильную версию Hysteria, берёт ожидаемый SHA‑256 из upstream `hashes.txt` и сверяет с ним скачанный артефакт;
|
||||
5. проходит compatibility gate: реальный бинарник Hysteria должен принять канонический конфиг HY2XS для Gecko и для Salamander;
|
||||
6. собирает orchestrator, frontend и backend, проставляя версию админки из контракта;
|
||||
7. прогоняет `go vet` и `go test` для HY2XS admin;
|
||||
8. проверяет граф зависимостей на известные уязвимости (`govulncheck ./...` и `pnpm audit` по всему lock‑графу);
|
||||
9. формирует архив и прогоняет acceptance‑проверки.
|
||||
|
||||
Любой сбой на шагах 1–7 останавливает сборку до создания пакета.
|
||||
Любой сбой на шагах 1–8 останавливает сборку до создания пакета.
|
||||
|
||||
Тесты и типы (шаги 2 и 6) — такой же обязательный гейт, как проверка
|
||||
Тесты и типы (шаги 2, 3 и 7) — такой же обязательный гейт, как проверка
|
||||
зависимостей: переменной, которая их отключает, не существует. Готовый пакет
|
||||
объявляет об этом полем `tests_gate=true` в `metadata/package.env`, и это
|
||||
утверждение опирается на фактический прогон, а не на намерение.
|
||||
|
||||
Для локальной работы обходить нечего: `bun test`, `bun x tsc --noEmit`,
|
||||
`go vet ./...` и `go test ./...` запускаются напрямую и tarball не создают.
|
||||
`go vet ./...`, `go test ./...` и
|
||||
`bun test tools/test/frontend-sprite.test.ts tools/test/frontend-contract.test.ts`
|
||||
запускаются напрямую и tarball не создают.
|
||||
|
||||
Переменные, управляющие выбором версии Hysteria:
|
||||
|
||||
@@ -1087,9 +1090,16 @@ tar -tzf dist/hy2xs-install-1.0.0.tar.gz | grep -E \
|
||||
├── package/ # skeleton будущего install package
|
||||
├── tools/build/ # production builder и packaging pipeline
|
||||
├── tools/dev/ # doctor: сверка среды разработки с versions.env
|
||||
├── tools/test/ # end-to-end проверки с реальным клиентом Hysteria
|
||||
├── tools/test/ # e2e с реальным клиентом Hysteria и контракты панели
|
||||
├── tools/legacy/ # purge-v0.sh: очистка сервера от предыдущего поколения
|
||||
├── docs/ # спецификации baseline, тестов и эксплуатации
|
||||
├── docs/ # документация, разложенная по слоям
|
||||
│ ├── architecture/ # baseline-модель и рамки
|
||||
│ ├── build/ # builder layer и состав пакета
|
||||
│ ├── runtime/ # оркестратор, systemd, post-install
|
||||
│ ├── admin/ # HY2XS admin и контракты панели
|
||||
│ ├── operations/ # runbook, разбор отказов, очистка 0.x
|
||||
│ ├── testing/ # набор проверок по слоям
|
||||
│ └── acceptance/ # отчёты о фактических прогонах приёмки
|
||||
├── versions.env # контракт продукта, платформы и toolchain
|
||||
├── CHANGELOG.md
|
||||
├── README.md
|
||||
@@ -1098,6 +1108,8 @@ tar -tzf dist/hy2xs-install-1.0.0.tar.gz | grep -E \
|
||||
|
||||
Каталог `dist/` создаётся builder’ом и не должен храниться в git.
|
||||
|
||||
Точка входа в документацию — [docs/README.md](docs/README.md).
|
||||
|
||||
## Для кого этот проект
|
||||
|
||||
HY2XS рассчитан на операторов, которым нужен воспроизводимый способ поставить Hysteria2‑сервер с локальной панелью управления, не собирая проект на production‑сервере и не открывая admin UI наружу.
|
||||
|
||||
Reference in New Issue
Block a user