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
+44 -14
View File
@@ -3,7 +3,6 @@ set -euo pipefail
STAGE_DIR="tools/build/output/hy2xs-install"
ADMIN_BUILD_DIR="tools/build/output/hy2xs-admin-build"
HYSTERIA_LOCK_FILE="tools/build/hysteria-lock.env"
prepare_stage() {
local version="$1"
@@ -27,6 +26,38 @@ prepare_stage() {
printf '%s\n' "$build_id" >"$STAGE_DIR/metadata/package.build_id"
}
run_orchestrator_tests() {
if [ "${SKIP_TESTS:-false}" = "true" ]; then
log_info "WARNING: orchestrator tests skipped (SKIP_TESTS=true)"
return 0
fi
(
cd orchestrator
"$BUN_BIN" install --frozen-lockfile
"$BUN_BIN" x tsc --noEmit
"$BUN_BIN" test
) || fail "orchestrator contract tests failed"
}
run_admin_tests() {
if [ "${SKIP_TESTS:-false}" = "true" ]; then
log_info "WARNING: HY2XS admin tests skipped (SKIP_TESTS=true)"
return 0
fi
# `go:embed all:dist` требует собранных frontend-ассетов, поэтому эта
# функция должна вызываться только после bundle_ui.
[ -d "${UI_SRC:-apps}/frontend/dist" ] \
|| fail "run_admin_tests must run after bundle_ui: ${UI_SRC:-apps}/frontend/dist is missing"
(
cd "${UI_SRC:-apps}"
GOTOOLCHAIN=local "$GO_BIN" vet ./...
GOTOOLCHAIN=local "$GO_BIN" test ./...
) || fail "HY2XS admin contract tests failed"
}
build_orchestrator() {
local bun_compile_target="${BUN_COMPILE_TARGET:-bun-linux-x64}"
@@ -88,19 +119,13 @@ write_metadata() {
dirty_tree="true"
fi
[ -f "$HYSTERIA_LOCK_FILE" ] || fail "missing Hysteria lock file: $HYSTERIA_LOCK_FILE"
# shellcheck disable=SC1090
. "$HYSTERIA_LOCK_FILE"
[ -n "${HYSTERIA_VERSION:-}" ] || fail "HYSTERIA_VERSION is required in $HYSTERIA_LOCK_FILE"
[ -n "${HYSTERIA_ARTIFACT_URL:-}" ] || fail "HYSTERIA_ARTIFACT_URL is required in $HYSTERIA_LOCK_FILE"
[ -n "${HYSTERIA_ARTIFACT_SHA256:-}" ] || fail "HYSTERIA_ARTIFACT_SHA256 is required in $HYSTERIA_LOCK_FILE"
case "$HYSTERIA_ARTIFACT_SHA256" in
replace-with-*|"")
fail "HYSTERIA_ARTIFACT_SHA256 must be a real release sha256"
;;
esac
printf '%s' "$HYSTERIA_ARTIFACT_SHA256" | grep -Eq '^[a-fA-F0-9]{64}$' \
|| fail "HYSTERIA_ARTIFACT_SHA256 must be a 64-char hex SHA256"
# Значения приходят из resolve_and_verify_hysteria: они уже проверены
# по SHA-256, по `hysteria version` и по compatibility gate.
[ -n "${HYSTERIA_VERSION:-}" ] || fail "HYSTERIA_VERSION was not resolved before write_metadata"
[ -n "${HYSTERIA_ARTIFACT_URL:-}" ] || fail "HYSTERIA_ARTIFACT_URL was not resolved before write_metadata"
[ -n "${HYSTERIA_ARTIFACT_SHA256:-}" ] || fail "HYSTERIA_ARTIFACT_SHA256 was not resolved before write_metadata"
validate_hysteria_version_format "$HYSTERIA_VERSION"
validate_hysteria_sha256_format "$HYSTERIA_ARTIFACT_SHA256"
{
printf 'name=HY2XS\n'
@@ -127,11 +152,16 @@ write_metadata() {
printf 'hysteria_version=%s\n' "$HYSTERIA_VERSION"
printf 'hysteria_artifact_url=%s\n' "$HYSTERIA_ARTIFACT_URL"
printf 'hysteria_artifact_sha256=%s\n' "$HYSTERIA_ARTIFACT_SHA256"
printf 'hysteria_channel=%s\n' "${HYSTERIA_CHANNEL:-unknown}"
printf 'hysteria_resolution=%s\n' "${HYSTERIA_RESOLUTION:-unknown}"
printf 'hysteria_resolved_at=%s\n' "${HYSTERIA_RESOLVED_AT:-unknown}"
printf 'hysteria_compat_gate=%s\n' "${HYSTERIA_COMPAT_GATE:-unknown}"
} >"$STAGE_DIR/metadata/package.env"
printf '%s\n' "$HYSTERIA_VERSION" >"$STAGE_DIR/metadata/hysteria.version"
printf '%s\n' "$HYSTERIA_ARTIFACT_URL" >"$STAGE_DIR/metadata/hysteria.url"
printf '%s\n' "$HYSTERIA_ARTIFACT_SHA256" >"$STAGE_DIR/metadata/hysteria.sha256"
printf '%s\n' "${HYSTERIA_RESOLUTION:-unknown}" >"$STAGE_DIR/metadata/hysteria.resolution"
(
cd "$STAGE_DIR"