Удалённые проекты: правки прямо на сервере по SSH
Самая свежая арка (и она ещё не закрыта на момент блога). До неё Verstak работал только с локальными папками: выбрал проект на диске — агент его правит. Но реальная задача звучала иначе:
«Окей, выбрали проект. А если я хочу работать через SSH или GitHub — короче, в облаке?»
И ключевое решение Павла: делать обе модели сразу.
Две модели, не одна
- Вариант A — git-клон. Даёшь
https://…илиgit@host:owner/repo— Verstak клонирует репозиторий в~/.verstak/projectsи дальше работает с ним как с обычным локальным проектом (+ push/PR). Переиспользует вообще всё: тулзы, undo, карту проекта. Размер — M. - Вариант B — ssh-live. Даёшь
user@host:/var/www/site— и агент правит файлы прямо на сервере по SSH. Никакого клона, изменения сразу в бою. Для живого сайта (например, agi-iri.ru). Размер — L, потому что это правки прод-сервера.
Это не «или-или». Иногда хочется безопасно через git, иногда — быстро прямо на сервере. Verstak даёт оба пути.
Как роутится Вариант B
Здесь окупилась архитектура из поста про устройство. Все файловые тулзы агента ходят через интерфейс FileTools. Значит, чтобы перенаправить чтение/запись/команды на сервер, не нужно трогать ни один handler — достаточно подменить реализацию FileTools.
Точка роутинга получилась элегантной. project_path для ssh-проекта — это ssh://[user@]host/remotePath, и он самоописывающий: из него парсится всё нужное, БД не требуется. Диспетчер:
createToolsForProject(projectPath, signal):
ssh://… → ssh-backend (правки на сервере)
иначе → локальная ФС
Один if на входе. Локальные проекты — нетронуты на 100%.
Под капотом ssh-backend:
parseSshProjectPath— разбираетssh://…обратно в{user, host, remoteRoot};createSshBackend—readFile/writeFile/listDir/runCommandчерез системныйssh;makeSshExec— реальный вызов ssh с ключом иBatchMode, инъектируемый (в тестах подменяется на mock, поэтому всю логику можно проверить без живого сервера).
Шесть тулзов (read_file / write_file / apply_patch / list_directory / search_project / run_command) теперь роутятся на сервер для ssh-проектов. И что приятно — confirm-flow (показать дифф, подтвердить запись) тоже ходит через FileTools.execute, поэтому подтверждение правок на сервере работает само, без отдельного кода.
Безопасность — заложена сразу, не «потом»
Править прод-сервер — это страшно по умолчанию. Поэтому защита встроена в ядро:
- escape-guard.
resolveRemotePathне даёт выйти за корень проекта:../../../etc/passwd→ отказ. Это самая важная чистая функция здесь, и она покрыта тестами в первую очередь. - ssh-denylist.
rm -rf /,mkfs, запись в/etcи прочие опасные команды блокируются — переиспользован классификатор из SSH-коннектора. - mode-policy. Запись на сервер подтверждается так же, как локальная правка.
- secret-scanner на чтении — ключи с сервера не утекут в контекст.
12 тестов на ssh-backend, включая security-кейсы (через mock exec). Type ✓, build ✓, suite 1171 ✓.
Чего ещё нет (честно)
- Реальный ssh-exec нужно проверить вживую. Юнит-тесты гоняют логику через mock; настоящий прогон против сервера — обязателен на безопасном пути (
/tmp/verstak-test), а не сразу на корне боевого сайта. Это я не могу подтвердить автономно — нужен живой тест. - Undo для удалённых файлов — локальный undo не откатывает ssh-файлы. Отдельный шаг.
- UI «Добавить проект» с выбором источника (папка / GitHub / SSH) — зона Ильи.
- Деградации для ssh: карта проекта и user-layer пока читают локальную ФС. Полиш, не поломка.
Почему это правильный паттерн
FileTools как единая абстракция позволила добавить целый новый режим работы (правки на удалённом сервере) аддитивно — одним диспетчером и новым бэкендом, не переписывая agent loop и не рискуя локальными проектами. Это и есть дивиденд от того, что в начале мы не пожалели времени на чистые границы между слоями.
На этом дев-блог догоняет настоящее. Дальше — живая проверка SSH, undo для удалённых, UI выбора источника. И, наверное, новые грабли, которые станут постом №8.