11 KiB
SSH Manager — постоянные и разовые права
Проверено и развёрнуто: 2026-10-19 22:19 UTC+6 (Asia/Bishkek).
SSH Manager 0.4.0, implementation commit d2806ac150363712b8baa9c40dbd37f2946b8c13. Рабочее дерево чистое при сборке, vcs.modified=false. Активный binary SHA256 536d389a4261e186fce8dfabe4a3adfe605d190d84ef188cdf105c3e8ee079bd, inode работающего процесса совпадает с установленным файлом. HTTP MCP 127.0.0.1:17796/mcp отдаёт 13 инструментов.
Balda остаётся на чистом upstream 138cc4a71d6889de30fe90e368f27f129fd8d792, binary SHA256 31c448af84428f83491d5fb8317549466f814f51c453de11fc8f6c9bd0836672. Каталог/кэш MCP обновлён штатным перезапуском: 2026-10-19T16:15:26.785581969Z. Config/env/mounts, OAuth login, SSH inventory и ключи сохранены; health/login 200, Mattermost websocket подключён. Все 49 runtime sessions и metadata, 28 questions, 2 users/bindings и 24 archive sessions из остановленного snapshot сохранены. Workspace Manager не менялся.
Что исправлено
В разобранном треде штатный ключ уже работал, но bubblewrap закрывал сеть хоста, Docker socket и sudo. Модель попыталась использовать sandbox-доступ Mac как административный и запустить вложенный ssh kraken; он завершился DNS-ошибкой. Прав не поменялось. У менеджера тогда отсутствовало API изменения профиля. Сбой произошёл до обновления Balda на upstream.
Теперь изменения выполняются через SSH Manager существующим операторским bootstrap-доступом, без передачи его ключей агенту и без хардкода хоста. Менеджер не получил инструмент произвольного выполнения команд: он выдаёт разрешение и native SSH-команду, которую запускает клиент своим установленным ключом.
Права
network: сеть хоста вместо отдельного Linux network namespace; на Mac — IP networking через Seatbelt.read_paths/write_paths: конкретные канонические пути. Manager control state, личные SSH credentials, системные корни и каталоги с socket-файлами не выдаются обычным файловым grant. Linux использует проверенные открытые FD для bind mounts.docker:none,readилиmanage. Read разрешает просмотр/логи/инспекцию, но не изменения. Docker CLI работает с фиксированным локальным daemon endpoint и закрытым control HOME/config; socket не появляется в sandbox.admin: прямойsudoс уже существующими noninteractive правами оператора. Sudoers не изменяется. Native timeout запускается с теми же привилегиями, чтобы остановить обычную root-команду.
docker=manage и произвольный sudo могут обойти файловые/сетевые ограничения; форма подтверждения сообщает об этом. Это отдельные явно разрешённые исключения. Завершение вызова не откатывает его побочные эффекты и не обещает отозвать намеренно оставленную привилегированную работу.
Постоянное изменение
ssh_permissionsвозвращает профиль и revision.ssh_permissions_update: полный новый профиль плюсexpected_revision.- Native owner form показывает before/after; затем выполняются реальная приёмка изоляции, CAS только managed key line и SSH-проверка из настроенного клиента. Ключ и маршрут сохраняются.
- Ошибка активации/проверки восстанавливает и проверяет прежний профиль либо явно сообщает, что rollback не подтверждён.
Новые вызовы используют новый профиль. Старые запущенные процессы не завершаются; неиспользованные разовые допуски инвалидируются. Действующие production mac и kraken пока возвращают managed=false: их прежние принятые ограничения при deployment не заменялись. Первый переход на управляемый профиль — отдельное явное ssh_permissions_update с owner confirmation, выполняемое самой Balda через MCP; ручная настройка JSON/хоста не требуется.
Разовый вызов
ssh_call_request принимает хост, точный argv и только временные overrides профиля. Например: command ["docker","ps","-a"], permissions {"docker":"read"}.
Одно owner confirmation связывает хост, argv, эффективные права и сроки. Затем Balda запускает возвращённый ssh_command своим установленным ключом. Сервер атомарно потребляет id до запуска, включая ошибочные вызовы; повтор/гонка второго подключения не дают второго запуска. Argv исполняется буквально, stdin закрыт. Start TTL 1–900 секунд (default 300), runtime 1–600 секунд (default 60). Часы — общесистемные на целевом хосте, включая macOS system Python.
ssh_call_status читает серверную квитанцию; issued не означает выполнение, consumed без result не означает, что процесс ещё работает. Успех — finished и exit_code 0 после реального SSH. ssh_call_cancel подтверждённо отменяет неиспользованный допуск, но не останавливает запущенную команду. Изменение профиля и revoke не воскрешают старые разрешения при повторной регистрации.
Постоянный профиль при разовом вызове не меняется. Штатная политика Balda для запуска локальной SSH-команды остаётся отдельным уровнем; SSH grant не выключает её. Старые диалоги с кэшированной MCP schema обновляются обычной новой сессией / /reset; история автоматически не сбрасывалась.
Проверено
- Go race и vet, diff --check — pass.
- Native macOS + MCP + временный sshd: 22 проверки, включая отказы, stale revision, rollback после сбоя SSH-проверки, буквальный argv, закрытый stdin, race двух соединений, consumption после ошибки, TTL/timeout/cancel, постоянные file/network права и отзыв/re-authorize.
- Linux strict bubblewrap в Colima: 10 проверок, в том числе Docker read/manage отдельно, отказ управления при read, sudo от обычного пользователя с получением host root и остановка root-команды по тайм-ауту. Kernel/AppArmor/proc protection не ослаблялись. Временный Docker volume удалён.
- Прежний native lifecycle произвольных хостов/ProxyJump/pin/restart/revoke/remove: 14 проверок.
- Реальная модель в работающей Balda: session
01a154e9-5b6a-7a32-ae5b-d5efcdc03ca6. Постоянный update → one-call → проверка серверной квитанции → восстановление профиля. Ровно 3 native owner forms для этих 3 изменений, без generic MCP approval. Harness выполнил pinned native SSH из реального контейнера UID 1000 установленным временным fixture-ключом; успех подтверждён, повтор запрещён, исходная сеть восстановлена. - После deployment свежий Codex ACP вызвал новый
ssh_permissionsна production Mac/Kraken: session01a154f0-1bb2-7932-aa2d-cf2907fc4ed0, 0 подтверждений. Это read-only проверка установленного API, без миграции профилей. - После перезапуска Balda прежние production-ключи к Mac и Kraken ещё раз проверены native SSH из настоящего UID 1000 Balda; оба вернули случайный marker.
Тесты используют случайные aliases/порты, временные ключи и отдельные private пути. Тестовые сообщения в Mattermost не отправлялись. Никакие bootstrap keys/passwords не передавались модели или в agent volume.
Evidence: /Users/admin/.local/share/balda-workspace/candidate/ssh-permissions-20261019. Backup менеджера: /Users/admin/.local/share/balda-workspace/backups/ssh-permissions-20261019T161039Z. Согласованный state backup Balda: /Users/admin/.local/share/balda-workspace/backups/ssh-permissions-balda-20261019T161515Z. Backup изменённых заметок: /Users/admin/.local/share/balda-workspace/backups/obsidian-ssh-permissions-20261019T221941+0600.
Исходники и contract: /Users/admin/Developer/ssh-manager/README.md, docs/permissions-2026-10-19.md. Текущий setup: personal/projects/balda/setup. План: personal/plans/balda-remote-agent.