feat(v1): Gecko-обфускация, latest-stable Hysteria на сборке и forward-compatible admin

Сквозная миграция HY2XS на современную Hysteria (2.12.2) и переход на v1.

Build:
- версия Hysteria резолвится на этапе сборки из HyNetworks/hysteria и
  замораживается в metadata пакета (version + immutable url + sha256);
- compatibility gate: реальный бинарник должен принять канонический конфиг
  HY2XS для gecko и salamander до создания пакета;
- сборка прогоняет тесты оркестратора и админки.

Конфигурационный контракт:
- HY2XS_CONFIG_SCHEMA_VERSION=2, чужая схема отклоняется fail-fast;
- obfs стал настоящим union gecko|salamander, gecko — default;
- obfs-блок рендерится оркестратором целиком, два подтипа одновременно
  структурно невозможны;
- современный baseline: congestion bbr/standard, disableLossCompensation=false,
  disableStatelessReset=false, полный quic-блок.

Исправления:
- share URI для gecko: генератор был завязан на Obfs.Salamander.Password и
  выдавал нерабочую ссылку при любой другой обфускации;
- SNI брался только из ACME-блока и уходил пустым при HY2XS_TLS_MODE=file;
- экспорт конфига выносил trafficStats.secret, access_token и obfs-пароль;
- экспорт терял неизвестные upstream-поля при round-trip через типизированную
  модель;
- renderRuntimeEnv печатал тип обфускации литералом, расходясь с конфигом;
- namedotcom удалён из ACME-реестра (нет в Hysteria с 2.11.0).

Тесты:
- 95 тестов оркестратора: env, рендер, семантика профиля, резолвер, rollover;
- тесты URI и экспорта в Go;
- tools/test/e2e-hysteria.sh с реальным клиентом Hysteria.

UX:
- подсказки и примеры в форме создания пира.

Прочее: CHANGELOG.md, .gitattributes (LF для target-side файлов),
документация на русском.
This commit is contained in:
2026-08-27 08:15:02 +05:00
parent 0205334cd8
commit ddf0ddf71e
53 changed files with 4827 additions and 291 deletions
+81 -13
View File
@@ -43,13 +43,17 @@ Builder не является частью target install flow: на target serv
## Что делает builder
1. Проверяет структуру проекта.
2. Собирает / подготавливает HY2XS admin.
3. Компилирует оркестратор из Bun/TypeScript в install-артефакт.
4. Копирует артефакты UI в package staging directory.
5. Кладёт entrypoint, templates, docs и service files.
6. Формирует итоговый install package.
7. При необходимости считает manifest/checksum.
8. Выдаёт один переносимый результат для target machine.
2. Прогоняет тесты и типы оркестратора.
3. Разрешает upstream-версию Hysteria и проходит compatibility gate.
4. Компилирует оркестратор из Bun/TypeScript в install-артефакт.
5. Собирает / подготавливает HY2XS admin.
6. Прогоняет тесты HY2XS admin (после сборки frontend: `go:embed all:dist` требует готовых ассетов).
7. Копирует артефакты UI в package staging directory.
8. Кладёт entrypoint, templates, docs и service files.
9. Формирует итоговый install package.
10. Считает manifest/checksum.
11. Проверяет архив и прогоняет acceptance-проверки.
12. Выдаёт один переносимый результат для target machine.
## Что builder не делает
@@ -119,14 +123,76 @@ project/
Сам бинарь Hysteria2 **не вендорится** в install package как baseline-правило.
Причина:
- ядро Hysteria рассматривается как stable upstream component
- целевая установка должна брать его с official upstream на момент развёртывания
- ядро Hysteria рассматривается как stable upstream component;
- целевая установка скачивает его с official upstream, но **строго по замороженным координатам**.
### Разрешение версии на сборке
```text
SOURCE
resolve latest stable (HyNetworks/hysteria, только теги app/vX.Y.Z)
resolve exact release asset (hysteria-linux-amd64)
download + compute SHA-256
compatibility gate (реальный бинарник принимает канонический конфиг HY2XS)
PACKAGE METADATA
version = vX.Y.Z
exact_url = <immutable release asset>
sha256 = <...>
resolution = latest-stable | pinned | override
TARGET SERVER
скачивает уже конкретный неизменяемый артефакт
```
Так одновременно выполняются оба требования: «по умолчанию брать последнюю стабильную» и «production-установка должна быть детерминированной и проверяемой».
Переменные builder:
| Переменная | Значение по умолчанию | Назначение |
| --- | --- | --- |
| `HYSTERIA_CHANNEL` | `stable` | `stable` — разрешить последнюю стабильную через upstream API; `pinned` — взять `tools/build/hysteria-lock.env` без сети |
| `HYSTERIA_VERSION_OVERRIDE` | пусто | Закрепить конкретную версию `vX.Y.Z` |
| `HYSTERIA_COMPAT_GATE` | `true` | Compatibility gate; для release-сборок обязателен |
| `HYSTERIA_WRITE_LOCK` | `false` | Записать разрешённые значения обратно в `tools/build/hysteria-lock.env` |
| `GITHUB_TOKEN` | пусто | Опционально, чтобы не упереться в anonymous rate limit |
Дополнительно:
- версия Hysteria2 фиксируется в metadata install package (`metadata/hysteria.version`);
- URL артефакта и SHA256 фиксируются в metadata install package (`metadata/hysteria.url`, `metadata/hysteria.sha256`);
- версия, URL и SHA256 фиксируются в metadata install package (`metadata/hysteria.version`, `metadata/hysteria.url`, `metadata/hysteria.sha256`);
- способ выбора версии фиксируется в `metadata/hysteria.resolution` и `metadata/package.env`;
- runtime `reconfigure` не обновляет и не откатывает бинарник Hysteria2;
- install flow валидирует SHA256 и фактическую версию установленного бинарника.
- install flow валидирует SHA256 и фактическую версию установленного бинарника;
- install-time код не обращается к upstream API и не использует moving `latest` — это проверяется тестами и acceptance-шагом сборки.
### Compatibility gate
Gate защищает от ситуации, когда upstream меняет схему конфигурации, а builder молча собирает неработающий HY2XS.
Порядок:
1. скачать артефакт и сверить SHA-256;
2. сверить `hysteria version` с разрешённой версией;
3. отрендерить канонический конфиг HY2XS тем же кодом, что работает на target (`orchestrator/tools/render-canonical-config.ts`);
4. запустить реальный бинарник Hysteria с этим конфигом — для Gecko и для Salamander;
5. только после этого собирать release package.
При несовместимости ломается сборка:
```text
BUILD FAILED: unsupported Hysteria stable v2.13.0
```
Это осознанно: ошибка должна проявиться на build machine, а не на сервере оператора.
## Инварианты
@@ -137,4 +203,6 @@ project/
3. на сервере нет отдельного build step
4. bundled UI уже находится внутри пакета
5. оркестратор authored as Bun/TypeScript, но на target приходит как готовый install-артефакт
6. Hysteria2 подтягивается install layer'ом с upstream, а не собирается на target из исходников
6. Hysteria2 подтягивается install layer'ом с upstream по замороженным координатам, а не собирается на target из исходников
7. выход новой версии Hysteria после сборки не меняет содержимое уже собранного пакета
8. несовместимый upstream ломает сборку, а не установку у пользователя