- Зачем:
- CLI и спека были переусложнены относительно принятой модели угроз
(один пользователь, доверенная машина): лишняя ось версий Xray и
защита от входов, которые не возникают при ручном редактировании.
- Что:
- убрана поддержка Xray 25.12.8 — поддерживается только 26.3.27;
allowInsecure валидируется, но никогда не эмитится в JSON.
- удалена проверка владения сокетом через /proc/net/tcp; идентичность
процесса и сверка адрес/порт со state сохранены.
- валидация INI/профиля/адреса/query сведена к отказам на реальные
опечатки; scoped IPv6 отклоняется одинаково на Python 3.8 и 3.9+.
- удалены fsync/O_EXCL-церемония, SIGALRM-таймер, zombie-инспекция,
мёртвый отпечаток профиля и двойной разбор extra/alpn.
- shell.bash принимает вывод env без ре-валидации, сохранив атомарность;
спека и issue 01–05 приведены к новому объёму (тикет 06, леджер).
- Проверка:
- python3 -m unittest discover -s tests — 34 теста OK.
- bash tests/test_proxy_launchers.sh — 8 проверок PASS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
15 KiB
06 — Упрощение: срез accidental-сложности спеки и кода
What to build: Один проход упрощения по готовым issue 01–02 и спеке: убрать поддержку второй версии Xray, избыточные защитные проверки вне принятой модели угроз («доверенные пользователи машины», единственный пользователь редактирует свои файлы сам) и церемонии, не нужные личному foreground-инструменту. Поведенческие контракты из раздела «Не трогать» сохраняются без изменений.
Blocked by: 02 — Управляемый Xray: полный штатный путь.
Status: done
Резолюция (2026-07-20): реализовано и принято. Дельта: CLI 1123→976, shell.bash 116→91, тесты 1357→1236 строк; сьюты: 34 unittest OK + 8 shell PASS. Ревью: 1 MAJOR (scoped IPv6 в упрощённом валидаторе — починен с регрессионным тестом под Python 3.8), 1 NIT отклонён аргументированно. Non-gating замечания ревью приняты как риски модели угроз.
Сначала прочитать:
- Этот файл целиком, затем
/tmp/xray-simplify-Zeo5/06-simplify/sweep.md— там точный line-level blast radius каждого пункта (секция 2 — срезы A/B, секция 3 — SIMP-N). Номера строк — ориентир, сверяй с фактическим кодом. docs/specs/2026-07-15-headless-xray-proxy-design.md— исходная спека.xray-proxy/.local/bin/xray-proxy,xray-proxy/.config/xray-proxy/shell.bash,tests/test_xray_proxy.py,tests/test_xray_proxy_managed.py.
Команды проверки (обе обязательны):
python3 -m unittest discover -s tests— baseline до изменений: 38 тестов, OK, ~60 с;bash tests/test_proxy_launchers.sh— baseline: 9 проверок PASS.
После изменений тестов станет меньше (удаляются тесты срезанных фич); все оставшиеся зелёные, новые счётчики указать в отчёте.
A. Срез dual-version: остаётся только Xray 26.3.27
VERSION_LINEпринимает только26.3.27; параметрversionубран из сигнатурparse_vless,build_xray_config,safe_summary,warn_legacyи их вызовов;xray_versionостаётся воротами «поддержанная версия или отказ» и по-прежнему показывает фактическую версию в сводке.- Ветка эмиссии
allowInsecureдля 25.12.8 и запретpcs/vcnдля 25.12.8 удалены.parse_boolean_fields(валидация точныхtrue/false, требование согласованности обоих полей, предупреждение при истинном значении) сохраняется;allowInsecureникогда не попадает в JSON. - Тестовая ось версий схлопнута: lifecycle-тест гоняет один прогон
26.3.27 (обе локации профиля — default и
-f— сохраняются);test_old_version_preserves_explicit_legacy_insecureи все 25.12.8-строки табличных тестов удалены.
B. Срез проверки владения сокетом через /proc/net/tcp
process_owns_listener,process_socket_inodes,decode_proc_addressи их вызовы (вverify_managed_stateи readiness-циклеcommand_start) удалены. Сохраняются: сверка PID/идентичности процесса, сверка адрес/порт машинного конфига со state иcheck_endpoint-проверка доступности порта.test_verified_child_must_own_configured_listenerудалён вместе с веткойFAKE_XRAY_LISTEN_PORTв фейковом xray;test_substituted_machine_port_fails_closed...сохраняется и зелёный.- Диагностические сообщения, упоминающие проверку владения слушателем
(в
verify_managed_stateи readiness-циклеcommand_start), обновлены: после среза они описывают фактические проверки (идентичность процесса, сверка адрес/порт, доступность порта), а не владение сокетом.
C. Диета входной валидации (файлы пишет сам пользователь)
validate_address: сначалаipaddress.ip_address, иначе минимальная проверка «непустое ASCII-имя без пробелов, схемы://,@,/и квадратных скобок». RFC-строгость по меткам DNS, лимит 253 и сопутствующие тесты удалены. Оборачивание IPv6 в[]при сборке URL сохраняется.load_config: сохраняется отказ на неизвестной секции/ключе и на отсутствии обязательного ключа (ловит реальные опечатки) и диапазон порта. Удалены: скан NUL, guard UTF-8-декодирования, отдельный запрет[DEFAULT], запрет CR/многострочных значений, case-sensitiveoptionxform; соответствующие подкейсы тестов удалены.read_profile: сохраняются разрешение симлинка, проверка прав (group/other → ошибка с подсказкойchmod 600) и правило «ровно одна непустая строка». Удалены скан NUL и guard UTF-8.parse_query: сохраняются отказ на неизвестном и на повторном query-параметре. Удалены regex на сырые%-последовательности и посимвольный запрет управляющих символов.
D. Диета церемоний
write_private_json: простая запись файла с правами 0600 внутри уже-0700 каталога; O_EXCL/fsync/os.replace/PID-суффиксы удалены.- Валидация
PROXY_PREFLIGHT_TIMEOUTиXRAY_PROXY_STOP_TIMEOUT— один guard «float()успешен и > 0, иначе понятная ошибка»;mathне импортируется; тесты экстремальных значений (nan/inf/1e-7/1e308) удалены. ДляPROXY_PREFLIGHT_TIMEOUTоставить один тест «плохое значение → понятный отказ»; дляXRAY_PROXY_STOP_TIMEOUTотдельного теста нет и добавлять его не нужно — достаточно guard'а. check_reachableиспользуетsocket.create_connection(timeout=...)без SIGALRM/setitimer-машинерии. Принятый риск (записан здесь): зависший DNS-резолв на external-пути не ограничен таймаутом — для личного инструмента пользователь прерывает вручную.extraиalpnразбираются один раз вparse_vless, результат сохраняется в профиле и переиспользуется вbuild_xray_configбез повторного разбора.parse_json_objectсохраняет оба отказа — на повторах ключей и на JSON-константах (reject_constantостаётся): существующий тест требует отказ на уровне разбора с диагностикой проextraи без запускаrun -test, и это дешевле, чем переносить ответственность на сериализацию.process_alive— толькоos.kill(pid, 0); чтение/proc/PID/statради zombie-состояния удалено.- Отпечаток профиля (
profile_fingerprint) удалён из state и кода: он не участвует ни в одном решении. Смена профиля по-прежнему блокируется существованием state. Вместе с ним обновленыSTATE_KEYSи все тестовые фикстуры state (включая точную сверку набора ключей в managed-тестах): устаревший ключ в фикстуре не должен ронять сверку ключей раньше, чем тест дойдёт до проверяемой идентичности процесса.
E. shell.bash: средняя форма приёма env
_proxy_apply_env_file: при ненулевом коде возврата CLI окружение не меняется вовсе; успешный вывод разбирается построчно по первому=; применяются (черезprintf -v, безeval) только восемь известных ключей, прочие строки — ошибка без частичного экспорта. Удалены сканы NUL/CR, отдельный детектор повторов и проверка «ровно восемь строк». Свойство «нет частичного изменения окружения при ошибке» сохраняется и остаётся покрыто тестом.tests/test_proxy_launchers.shприведён к средней форме: проверки повторов/CR/NUL/счётчика строк, соответствующие удалённой машинерии, убраны или переписаны; проверки «ненулевой код возврата CLI → окружение не тронуто», «неизвестная строка → ошибка без частичного экспорта» и владения функциями остаются зелёными.
F. Спека и соседние issue приведены к новому объёму
- Из спеки удалены: ветка 25.12.8 (все места из секции 2 sweep-файла),
флаги
-v/--debug(не реализованы), упоминание отпечатка профиля в state; описания валидации/атомарности смягчены до фактического поведения после этого issue. Формулировка идентичности процессов («PID + время старта + исполняемый файл») в спеке не меняется. - Issue 03: добавлен явный мандат «идентичность = PID + время старта
(
/proc/PID/stat) + исполняемый файл ребёнка / путь скрипта супервизора; текущий argv-обход заменить этим механизмом»; убраны унаследованные упоминания срезанных фич, если есть; строка Blocked by дополнена: «06 — Упрощение». - Issue 05: приёмка сведена к одной версии Xray 26.3.27; упоминания 25.12.8 удалены. Пункты про РЕД ОС сохранены (решение пользователя 2026-07-20: целевые системы шире Ubuntu — РЕД ОС, возможно Astra Linux и Alt Linux; инструмент могут использовать коллеги).
- В спеке в раздел ручной проверки добавлены Astra Linux и Alt Linux как кандидаты «по мере доступности» с тем же правилом, что для РЕД ОС: недоступная среда явно записывается как неподтверждённая, поддержка не заявляется без фактической проверки версии Python и прогона.
- В issue 01 и 02 добавлена одна строка после Status: «Часть
требований пересмотрена в 06 — см. 06-simplification-pass.md»; чекбоксы
01 и 02 не редактируются (issue 01 описывает строгую приёмку
env, которую этот issue смягчает, — без пометки он противоречил бы коду).
G. Не трогать (границы)
- Строгий отказ на неизвестном/повторном query-параметре VLESS.
- Точечный
stopтолько по проверенному PID; никакого pkill. - Foreground-супервизор, проброс сигналов, очистка state.
- Изоляция окружения
run(proxy-переменные только у ребёнка), сохранение argv и кода возврата,---разделитель. - Fail-fast
pclaude/pcodex, обратная совместимость: без машинного конфига — внешнийhproxy.local:12334. - Проверка прав файла профиля (chmod 600) и loopback-only вход.
- Авто-диагностика внешнего IP на старте (несмертельная) — остаётся.
- Секреты: полная VLESS-ссылка, UUID, ключи не появляются в stdout/stderr/ argv — все существующие тесты на это остаются зелёными.
bash/.bash_functions, установщик, README — не входят в этот issue.- Никаких коммитов.
Отчёт исполнителя
- Изменённые файлы со строкой «зачем» на каждый.
- Команда тестов и счётчик (все зелёные, указать новое число).
- Чекбоксы: закрыт / не закрыт и почему.
- Итоговая дельта
wc -lпо CLI, shell.bash и обоим тест-файлам против baseline (1123 / 116 / 467 / 890). - Сомнения, если есть.