# Упрощение proxy-client Status: ready-for-agent ## Зачем `proxy-client` — личный клиент для владельца и нескольких друзей, а не промышленное ПО. Большая часть кода и тестов — защита от сценариев, которые на личной машине не случаются (повторное использование PID, подложный state.json, zip-бомба в проверенном по SHA-256 официальном архиве, гонка `status` с параллельным `start`). Эта защита стоит сотни строк кода и тестов и около минуты прогона. Цель — оставить существенную сложность и убрать случайную. Принцип: **простой код, который честно делает своё дело и понятно сообщает об ошибке**. Не защищаемся от самого пользователя и от его собственных файлов. ## Что сохраняем (обязательное поведение) - Команды и их договор: `install [--replace]`, `status`, `env`, `run -- CMD`, `start [-f FILE]`, `stop`; коды выхода (2 без подкоманды, 127 — команда не найдена, 128+N — дочерний процесс убит сигналом N); восемь proxy-переменных. - Отказ без запасного пути: выбран Xray, но он не запущен — ошибка, а не переход на Hiddify. - Машинный INI: строгий формат как сейчас (он маленький и понятный). - Разбор VLESS: поддерживаемые TCP/REALITY и XHTTP/TLS, VLESS-шифрование `mlkem768x25519plus`, неизвестные query-параметры отклоняются. - Точная версия Xray 26.3.27 для `install` и `start` (сознательное решение). - Установка Xray: официальный архив, проверка SHA-256 по `.dgst`, атомарная замена через временный каталог рядом с назначением; `--replace` не пишет через симлинк; неудачная установка не портит старый бинарник. - `start` только на loopback-адресе; занятый порт — понятная ошибка. - Не выводим UUID, ключи REALITY и `path` XHTTP в stdout/stderr. - `client.json` и `state.json` — права 600 в каталоге 700 (в них секреты). - Один управляемый Xray за раз: блокировка `flock` на время `start`. - Остановка: Ctrl+C или `stop` гасят Xray и удаляют служебные файлы; если супервизор убит (SIGKILL), `stop` добивает оставшийся Xray и чистит файлы. - Python 3.8+ (у друзей старые дистрибутивы), только стандартная библиотека. ## Что упрощаем 1. **Проверка «тот ли процесс».** Вместо boot_id + starttime + `/proc/PID/exe` + разрешения argv супервизора относительно его cwd: Xray — PID жив и `/proc/PID/exe` совпадает с `xray_path`; супервизор — PID жив (и, если дёшево, его cmdline упоминает `proxy-client`). Непохожий процесс считаем мёртвым: сигнал не шлём, файлы считаем устаревшими и чистим. Состояние «не удалось подтвердить, удалите файлы вручную» исчезает. Двойная проверка под блокировкой при чистке устаревших файлов не нужна. state.json читаем без строгой схемы: битый файл — понятная ошибка с путём. 2. **Скачивание Xray.** Убрать три уровня ограничений размера, сверку Content-Length, строгую грамматику `.dgst`. Достаточно: скачать, найти в `.dgst` строку `SHA2-256=`, сравнить без учёта регистра. Убрать `O_EXCL`/0600 для кандидата внутри закрытого временного каталога и требование «каталог установки внутри $HOME». 3. **`install` и работающий Xray.** Замена бинарника под работающим процессом на Linux безопасна: не блокировать `install`, а напомнить перезапустить `start`. Блокировку start на время install не брать. 4. **Разбор ссылки.** `extra` — обычный `json.loads` + проверка, что это объект (без своих проверок повторных ключей и NaN: `xray run -test` проверит). `allowInsecure`/`insecure` — принимаются с любым значением и игнорируются; при истинном значении (`1`, `true`) — предупреждение. 5. **Установщик пакета `proxy-client/install.sh`.** Один способ — прямые симлинки (без Stow). Не перезаписывать чужие файлы и сообщить обо всех конфликтах сразу. Разрешить `~/.local` и `~/.config`, которые сами являются ссылками. Блок в `~/.bashrc` — дописать, если нет маркера; без разбора «повреждённых» блоков, поиска `.bash_custom` и точного текста `export PATH`. 6. **Подсказки об ошибках с файлами** называют файл полным путём и дают готовую команду. Пример: «файл профиля /home/u/.config/proxy-client/default.url доступен другим пользователям; выполните: chmod 600 /home/u/...». Если профиль — симлинк, называть конечный файл (права ставятся на него). ## Где живут тесты (согласовано с владельцем) 1. Команда `proxy-client`: argv → код выхода, вывод, созданные файлы, запущенные и остановленные процессы. 2. Разбор ссылки: `parse_vless` + `build_xray_config` (ссылка → JSON Xray) — быстрые табличные тесты без запуска процессов. 3. Установка Xray: `command_install` с подставляемым скачивателем. 4. Функции Bash: через поддельный исполняемый файл в `PROXY_CLIENT_BIN`. 5. Установщик пакета: через временный HOME. Больше нигде. Запрещено: подмена внутренних функций через `__globals__` / `mock.patch.dict`, проверки порядка внутренних вызовов, тесты тестовых подделок, по нескольку полных циклов start/stop ради одного утверждения. ## Задачи - `issues/01-cli.md` — CLI и Python-тесты. - `issues/02-installer-shell.md` — установщик пакета, shell-тесты, запускалка. - После 01 и 02 (делает оркестратор): привести разделы `docs/specs/2026-07-15-proxy-client-design.md` про установку, жизненный цикл, доставку, риски и проверку в соответствие с кодом; добавить в `proxy-client/README.md` ссылку на спецификацию для тех, кто меняет код.