# HY2XS 1.0.0-rc1 — отчёт build/host acceptance **Дата прогона:** 2026-09-01 **Вердикт:** `RC ACCEPTED WITH RELEASE-REQUIRED UX FIXES` Прогон выполнялся не как статический аудит исходного кода, а как фактическая release/host acceptance RC-сборки: сборка артефакта, установка на переустановленный Debian 13 и проверка работающего сервера. Release candidate: ```text Version: 1.0.0-rc1 Source commit: a1f0db22c2f6c0b0436789b64e82f53bfa314327 Artifact: hy2xs-install-1.0.0.tar.gz SHA-256: 7fd18a34f56ebb7e9cf62f579e857d6ed3f6a9711075a17da22818a4b079683c Target: Debian 13 / amd64 Hysteria: v2.12.2 Default obfs: gecko Fallback obfs: salamander ``` > Публичный IPv4 тестового хоста в отчёте заменён на `198.51.100.10` > (RFC 5737, документационный диапазон). Доменное имя и номер SSH-порта > оставлены: без них шаги прогона невоспроизводимы. --- ## 1. Что проверялось * воспроизводимость release build; * соответствие version contract; * тесты оркестратора; * typecheck и сборка frontend; * тесты Go; * гейты уязвимостей зависимостей; * разрешение и фиксация актуального stable Hysteria; * upstream SHA-256 Hysteria; * совместимость сгенерированной production-конфигурации с Gecko и Salamander; * содержимое готового release archive; * внутренние контрольные суммы пакета; * clean-host boundary; * read-only PHASE 0; * отказ установки поверх HY2XS 0.x; * фактическая чистая установка на переустановленный Debian 13; * systemd; * nftables takeover; * firewall rollback guard; * ACME; * runtime Hysteria; * runtime админки; * install-state; * `status`; * read-only `doctor`; * доступ к admin UI исключительно через SSH local forwarding; * базовые функциональные операции admin UI. Полный внешний Hysteria/Gecko dataplane через пользовательский desktop-клиент сознательно отложен до готовности собственного C#/sing-box клиента HY2XS. Это не подменяется server-side self-test — см. раздел 12. --- ## 2. Build acceptance Финальная release-сборка выполнена из `a1f0db22c2f6c0b0436789b64e82f53bfa314327`. Рабочее дерево перед сборкой было чистым. Orchestrator: ```text 399 pass 0 fail 932 expect() calls 18 test files ``` Hysteria: ```text Resolved stable: v2.12.2 Tag: app/v2.12.2 Published: 2026-08-23 ``` Upstream SHA-256: ```text 6493dfffd55b5883f64c76c63880ecc32988f0c568c9ca9014907877b4d55f94 ``` Скачанный бинарь совпал с upstream `hashes.txt`. Compatibility gate: ```text Gecko PASS Salamander PASS ``` Сгенерированная production-конфигурация HY2XS принята Hysteria `v2.12.2`. Frontend: ```text vue-tsc --noEmit PASS vite production PASS ``` Go: ```text go test PASS ``` Security: ```text govulncheck v1.7.0 PASS reachable vulns 0 pnpm audit high+ PASS high/critical vulns 0 ``` Полный release acceptance дошёл до: ```text [hy2xs-build] Built dist/hy2xs-install-1.0.0.tar.gz ``` Проверки release pipeline включают в том числе read-only installer boundary, семантику отката, firewall guard, сериализацию операций, транзакционный импорт пиров, редактирование секретов, гигиену зависимостей и обязательность test/security-гейтов. ### 2.1. Требование к памяти build-хоста Первый `govulncheck` был убит Linux OOM killer на машине с: ```text RAM: ~1.9 GiB Swap: 0 ``` После подключения временного swap 4 GiB полный security gate прошёл. Это не runtime-дефект HY2XS, но требование к сборочной машине: около 2 GiB RAM без swap может быть недостаточно для `govulncheck`. 4 GiB swap здесь — не формально доказанный минимум, а подтверждённая рабочая конфигурация данного прогона. См. [docs/build/02-build-layer-and-package.md](../build/02-build-layer-and-package.md). --- ## 3. Исправления release verifier, сделанные во время приёмки Приёмка выявила несколько ошибок не продукта, а самого release verifier. Они были исправлены до формирования принятого RC. ### 3.1. Ранний выход matcher'а и `pipefail` Обнаружен антипаттерн вида `printf … | grep -q …` при `set -o pipefail`. На достаточно большом выводе продюсера раннее завершение `grep -q` способно привести продюсера к `SIGPIPE`, и статус всей конструкции становится 141 — ненулевым именно тогда, когда совпадение НАЙДЕНО. 56 проверок переведены на форму без опасного pipeline. Кроме того, исправлена более существенная проблема: прежнее `2>/dev/null || true` превращало ошибку или опечатку в пути файла в пустой ввод, а отрицательная проверка после этого получала ложный PASS. Теперь отсутствие ожидаемого исходного файла — ошибка приёмки. Примечание: единичное первоначальное падение на LICENSE нельзя доказанно объяснить этим механизмом — размер LICENSE был ниже воспроизведённого порога буфера канала. После исправлений содержимое LICENSE, его копия в архиве и контрольные суммы подтверждены отдельно. ### 3.2. Проверки кода против комментариев Выявлены три ложных совпадения: `virtual:svg-icons-register`, прежние имена раннеров, `cancelFirewallRollback`. Все они находились в комментариях и прозе, а приёмка трактовала присутствие строки как возвращение исполняемого кода. Семантика гейтов исправлена: SVG проверяется по реальному runtime/build contract; определение раннера учитывает форму идентификатора; `cancelFirewallRollback` проверяется как declaration/call form, а не как любое упоминание строки. Наивный общий разбор `/* … */` намеренно не добавлен: неполный лексер может удалить настоящее содержимое внутри строкового или регулярного литерала и создать уже опасный ложный PASS. ### 3.3. Устаревший gate reconfigure Приёмка ожидала прежний вызов `classifyReconfigureFailure(ownership)` после того, как фактический контракт стал `classifyReconfigureFailure(ownership, error)`. Новая архитектура: ```text обычные ошибки -> классификация по ownership FirewallGuardFired -> типизированное исключение текст error.message -> не участвует ``` Gate приведён к фактическому контракту. --- ## 4. Artifact acceptance Release archive `hy2xs-install-1.0.0.tar.gz`, SHA-256: ```text 7fd18a34f56ebb7e9cf62f579e857d6ed3f6a9711075a17da22818a4b079683c ``` Хеш независимо пересчитан после копирования архива на Windows и совпал с серверным. Metadata пакета: ```text name=HY2XS license=AGPL-3.0-only version=1.0.0 release_line=1 config_schema_version=2 source_git_commit=a1f0db22c2f6 dirty_tree=false build_profile=production dependency_security_gate=true tests_gate=true hysteria_source=official-upstream hysteria_version=v2.12.2 hysteria_sha_source=upstream-hashes hysteria_channel=stable hysteria_resolution=latest-stable hysteria_compat_gate=true ``` Полный `sha256sum -c metadata/checksums.txt` для распакованного пакета завершился без ошибок. RC опубликован отдельным tag/release `v1.0.0-rc1`. --- ## 5. D0 — установка поверх legacy HY2XS До переустановки ОС RC был запущен на действующем сервере HY2XS 0.x. Ожидаемое поведение: ```text PHASE 0 → обнаружить legacy markers → завершиться до первой persistent mutation ``` Фактический результат: `RC=1`. Installer обнаружил старые: ```text /etc/hy2xs /etc/hysteria /var/lib/hy2xs /var/lib/hy2xs-admin /var/lib/hysteria /usr/local/lib/hy2xs /usr/local/bin/hysteria /usr/local/bin/hy2xs-orchestrator /etc/nftables.d/hy2xs.nft systemd units admin installation ``` и сообщил: ```text HY2XS v1 не поддерживает установку поверх и не мигрирует состояние 0.x. Ни один файл на сервере не изменён. ``` Контрольный before/after diff показал только изменение активной базы SQLite legacy-админки. Отдельный idle-тест без installer подтвердил, что `h_ui.db` сама меняет hash и mtime примерно каждые 20 секунд при работающем legacy `hy2xs-admin`. Следовательно: ```text D0 legacy detection PASS D0 fail-before-apply PASS D0 zero product mutation PASS ``` --- ## 6. Baseline чистого хоста Для дальнейшей проверки ОС была переустановлена. ```text Debian GNU/Linux 13 amd64 kernel 6.12.85+deb13-amd64 RAM ~1.9 GiB Swap 0 ``` Сеть: ```text 198.51.100.10/24 fi.api.withen.pro -> 198.51.100.10 ``` До установки: ```text HY2XS paths absent Hysteria paths absent HY2XS units absent Hysteria unit absent nft ruleset empty UDP 443 free TCP 80 free TCP 443 free ``` Единственный ожидаемый внешний listener — SSH :2323. Clean-host contract подтверждён фактическим составом хоста. --- ## 7. Чистая установка Установка выполнялась непосредственно из ранее созданного и проверенного RC artifact. Пакет не пересобирался на target-сервере. Production profile: ```text schema 2 domain fi.api.withen.pro public host fi.api.withen.pro public port 443 SSH 2323 firewall mode takeover staged firewall true admin bind 127.0.0.1 admin port 8080 admin public access false TLS ACME ACME challenge HTTP ACME email admin@withen.pro Hysteria port 443/udp obfs gecko IPv6 disabled DNS AAAA policy strict public endpoint policy strict ``` Результат: `INSTALL_RC=0`. Фактически прошли: ```text PHASE 0 package checksums clean-host preflight operation lock orchestrator bootstrap system dependencies capability preflight filesystem runtime env bundled admin Hysteria download Hysteria SHA verification config generation systemd installation firewall staged apply rollback guard post-install env bootstrap admin secret smoke firewall guard disarm durable install commit rollback cleanup ``` --- ## 8. Firewall До применения firewall создан rollback snapshot. Candidate-конфигурация проверена до активации: ```text nft -c -f hy2xs.nft.candidate nft -c -f nftables.conf.candidate ``` После этого создан transient rollback timer: ```text deadline: 45 s AccuracySec: 1 s RemainAfterElapse=no ``` Firewall применён только после успешного arm guard. После smoke: ```text guard disarmed installed state durably committed rollback files removed ``` Post-install: ```text rollback_guard_active=false rollback_guard_state=quiescent ``` Transient guard units отсутствуют. Candidate-файлы отсутствуют. В `/run/hy2xs/rollback` остался только пустой родительский каталог. Действующие правила: ```text table inet hy2xs input policy drop allow loopback allow established/related allow TCP/2323 IPv4 allow TCP/80 IPv4 allow UDP/443 IPv4 allow ICMP echo-request ``` --- ## 9. Состояние runtime Hysteria: ```text v2.12.2 active enabled UDP 0.0.0.0:443 trafficStats 127.0.0.1:36712 ``` Админка: ```text active enabled TCP 127.0.0.1:8080 ``` nftables: `active`, `enabled`. Let's Encrypt ACME: ```text authorization valid certificate obtained successfully ``` Install state: ```text product=hy2xs release_line=1 config_schema_version=2 product_version=1.0.0 installed=true phase=installed last_error="" ``` Секретные runtime-файлы имеют ограниченные permissions. `/usr/local/bin/hy2xs-orchestrator` является symlink, конечный исполняемый файл имеет `0755 root:root`. --- ## 10. `status` и `doctor` С корректным runtime `--package-dir`: ```text STATUS_RC=0 DOCTOR_RC=0 ``` `status` подтвердил: ```text services active firewall valid firewall entrypoint hy2xs-managed install generation current operation none rollback guard quiescent runtime state running install state installed ``` `doctor` прошёл preflight и smoke. Отдельно проверен read-only contract `doctor` — по фактическим PID процессов, а не только статическим тестом: ```text до doctor: hysteria PID = 5041, admin PID = 5042 после doctor: hysteria PID = 5041, admin PID = 5042 doctor Hysteria restart NO doctor admin restart NO ``` Post-install состояние systemd/firewall/install-state соответствует ожидаемому контракту. --- ## 11. Admin UI — ручная функциональная проверка Доступ: ```text SSH local forwarding 127.0.0.1:8080 ``` Публичный admin listener отсутствует. Проверены: вход, дашборд, список пиров, создание пира, генерация share URI. Дашборд получает данные CPU/RAM/disk/runtime. Создание пира фактически работает **при ручном указании секрета** — см. UX-02 в [перечне дефектов](2026-09-01-v1.0.0-rc1-ux-findings.md). Share URI формируется в ожидаемом production-формате: ```text hysteria2://@:443/ ?insecure=0 &obfs=gecko &obfs-password= &sni= # ``` Реальный секрет из тестовой URI в документацию не переносится. **Незакрытое действие среды:** одна тестовая URI была выведена за пределы admin UI, поэтому соответствующий тестовый пир перед дальнейшим использованием среды следует удалить или пересоздать с новым секретом. --- ## 12. Отложенная проверка Gecko E2E Полноценный внешний client E2E на этом прогоне не выполнялся. Причина не в обнаруженном server-side дефекте. Целевой пользовательский клиент HY2XS ещё разрабатывается: ```text C# sing-box core HY2XS desktop shell ``` Практически пригодных сторонних клиентов с необходимой Gecko-поддержкой недостаточно для того, чтобы считать их корректной reference implementation. При этом уже подтверждено: ```text Hysteria v2.12.2 Gecko config compatibility PASS Hysteria v2.12.2 Salamander compatibility PASS server startup PASS ACME PASS UDP/443 listener PASS peer auth/control-plane smoke PASS share URI generator PASS ``` Статус внешнего Gecko E2E: ```text DEFERRED — WAITING FOR HY2XS DESKTOP CLIENT ``` Он обязателен для окончательной ecosystem acceptance «server + client», но отсутствие стороннего Gecko-клиента не следует трактовать как отказ текущего server/orchestrator/admin RC. --- ## 13. Итоговый статус прогона ```text SOURCE AUDIT PASS BUILD PASS TEST GATE PASS SECURITY GATE PASS ARTIFACT INTEGRITY PASS LEGACY D0 PASS CLEAN HOST PASS FRESH INSTALL PASS ACME PASS SYSTEMD PASS NFTABLES PASS FIREWALL ROLLBACK GUARD PASS INSTALL STATE PASS STATUS PASS DOCTOR PASS DOCTOR READ-ONLY PASS ADMIN LOGIN PASS ADMIN DASHBOARD PASS PEER CREATE PARTIAL / UX DEFECT SHARE URI GENERATION PASS EXTERNAL GECKO CLIENT E2E DEFERRED EXTERNAL SALAMANDER E2E DEFERRED FINAL v1.0.0 NOT YET ACCEPTED ``` `v1.0.0-rc1` сохраняется как успешно прошедший server/install RC. Что требуется до финального `v1.0.0` — см. [перечень дефектов и план закрытия](2026-09-01-v1.0.0-rc1-ux-findings.md). --- ## 14. Замечания по шуму в логах прогона Две записи в журнале прогона к HY2XS отношения не имеют: * `ystemctl` — опечатка в shell; * пустой `journalctl -u hysteria-server --since '-2 min'` — ожидаемо, поскольку реального внешнего клиента в этот момент не подключали.