28 KiB
Workspace Gateway — план
2026-10-18 — исправлены MCP approvals и ответы 1
Лишний MCP tool-call approval убран в активных Codex-профилях штатным флагом моста --mcp-approval-policy=allow. Режим Balda остаётся ask. Точные подтверждения Workspace Connect/Renew и SSH Authorize/Revoke остаются обязательными. Подключённые MCP-серверы и их credentials не расширялись.
Upstream Codex ACP 1.11.0 требует elicitation capability, которой нет у текущего клиента Balda. В закреплённой сборке добавлен узкий fallback пустой confirmation-only формы на существующий ACP RequestPermission. Форма с полями и неподдержанные режимы без capabilities не принимаются автоматически. Explicit accept/decline/cancel и неизвестные ответы покрыты тестами. Чистая повторная сборка закреплённого source + patch прошла race/lint и дала одинаковый хеш.
В Balda исправлены две причины потерянного ответа: обычный 1 в DM теперь относится к единственному доставленному действующему вопросу той же беседы/сессии; ID отвечающего совпадает с исходным ID автора запроса, без добавления mattermost: только к ответу. Проверяются права отвечающего, expiry и время сообщения. Старый 1, в том числе в пределах той же секунды, не разрешает новый вопрос. Общие каналы и несколько pending-вопросов требуют ответа в треде.
Проверено:
- Настоящая цепочка Mattermost adapter → ChatFX → questions → SQLite:
1разрешает,2отклоняет; продолжение сохраняется для штатного возобновления. Wrong requester/session/conversation, expiry, недоставленный/неоднозначный вопрос, обычный текст и старое сообщение не выдают разрешение. - Полный
go test -race ./...: 173 пакета, exit 0; golangci-lint — 0 issues; go-arch-lint — OK. - Реальный Codex внутри production Balda: пять Manager lookup, запись в workspace и запрет записи вне него; generic permission requests = 0. Session
01a14fd8-a855-7bb2-ae76-77d5449db219. - Реальный
ssh_authorizeс возможностями клиента Balda дошёл до одного окна Owner confirmation; тест выбрал Decline и получил OWNER_DECLINED. Session01a14fd8-a84d-75d0-9624-ec816c3de844. Approved authorized_keys и registration journal не изменились. - Балda реально запущена из проверенной сборки: hash
/proc/1/exeсовпал со staged binary. Последний запуск:2026-10-18T16:41:07.023505736Z. HTTP health/login — 200; native SSH к Mac через обязательный Seatbelt — pass. State/home/work mounts сохранены; SQLite/compose/config backup —/Users/admin/.local/share/balda-workspace/backups/direct-reply-20261018T162446Z.
Коммиты: Balda 254f3e29; Workspace Manager/deployment 0c82b8f (основное MCP-исправление a5c0b66); SSH Manager 8739b1e. Рабочие деревья проверены отдельно. Подтверждение в реальном Mattermost-чате не отправлялось от имени владельца; приёмка входящего ответа выполнена сквозным тестом. Runtime evidence: ~/.local/share/balda-workspace/candidate/direct-reply-fix.json.
Kraken остаётся не настроен для execution: его filesystem isolation не provisioned/accepted; execution_ready=false сохранён. Инструмент теперь явно говорит, что chat approval не может подготовить хост, вместо ложного совета подтвердить несуществующее окно. Из Mac имя kraken не разрешается через DNS, оба IP из существующего SSH ProxyCommand (10.99.0.2, 10.99.1.2) не ответили на TCP 22; bootstrap SSH истёк на banner exchange. Запрошен доступный адрес/восстановление маршрута. Регистрация нового target-ключа и приёмка этого хоста не заявляются выполненными.
Ранее остававшиеся отдельные решения по личным Mac CLI credentials/OpenCode localhost этим исправлением не подменяются. Полная исходная настройка не помечена принятой.
Обновлено: 2026-10-18.
Проект: /Users/admin/Developer/workspace-gateway.
Git: main, реализация 00b7e13; актуальные deployment scripts и приёмка 9e5066a (2026-10-18). Четыре MCP-функции реализованы; принят native SMB3 backend с фактическим отзывом открытых FD на Linux и Mac, независимым истечением срока и динамическим подключением без рестарта получателя. Сервис установлен как user launchd job на 127.0.0.1:17795; аутентифицированные вызовы из доверенного образа Balda прошли. Production Balda переключена с явного разрешения владельца и перезапущена 2026-10-18 в 20:13:46 Asia/Bishkek: native ask активен, оба Manager проверены из рабочего контейнера, SSH/Seatbelt прошёл, HTTP health/login — 200. State/home/work, прежний pool и все записи БД сохранены; backup сделан до переключения. Полная модельная приёмка ещё ожидает отдельных решений по существующим CLI credentials и OpenCode localhost binding.
Исправления production: Codex workspace-write принят реальной моделью в обычном workspace и динамическом RW grant, запись вне разрешённых roots запрещена. Пять безопасных Manager-запросов прошли без approval; изменения прав по-прежнему требуют владельца. Старый broker отключён, оригинальные Prism сохранены. Принятые Docker-профили включены только с точного согласия владельца; privileged/SYS_ADMIN не добавлены. Журнал и повторяемый модельный тест включены в 1076b4f; SSH Manager — f876d37.
Корни проектов исправлены по замечанию владельца: только developer: /Users/admin/Developer. downloads был моей лишней настройкой и удалён из рабочего конфига и примера; дополнительные корни нельзя включать из примера без явного выбора владельца.
Приёмка 9e5066a: из рабочего контейнера получены 139 папок Developer, 8 дочерних папок workspace-gateway, регистронезависимый поиск имени — 2 мс. query фильтрует текущий уровень, глубокий обход включается только recursive: true; прежний неявный обход всех файлов/зависимостей упирался в лимит. Настоящий Codex сделал пять folder calls и вывел реальные корни/количество/имена, permission requests: 0. Отчёт candidate/project-discovery-acceptance.json, тест tests/balda_discovery_acceptance.py, ACP session 01a14fa7-60f2-7971-81de-b6c838ec1c31. Предыдущее заявление о полной проверке не включало просмотр внутри каждого рабочего root и было преждевременным.
Общий setup Balda: personal/plans/balda-remote-agent.
Назначение и четыре функции
Сервис выдаёт Balda и удалённым агентам доступ к исходным папкам через сетевую файловую систему. Balda и агенты видят одни и те же файлы; копирование Git-репозитория не считается реализацией общего доступа.
- Папки: листинг и навигация по папкам внутри настроенных корней (
developer,downloadsи других), а также поиск папок по имени; без выдачи списка файлов и их содержимого. - Подключение: выбранная папка появляется в work dir после подтверждения владельцем точного пути, получателя, режима доступа и срока.
- Отключение: фактический отзыв ранее выданного доступа.
- Лизинг: статус и срок действия, автоматический отзыв после истечения срока, продление с подтверждением владельца.
Четыре пользовательские функции — согласованный объём проекта. Обработка ответа владельца, журнал выданных разрешений и таймеры обслуживают эти функции, а не расширяют API прикладными сценариями.
Конфиг корней и поиск папок
Workspace Manager — пользовательское название сервиса; текущие путь проекта и имя этой заметки остаются workspace-gateway.
В конфиге задаются несколько именованных корней; список расширяется без изменения кода. Например:
roots:
developer: /Users/admin/Developer
Корень задаёт область обнаружения папок, а не автоматический доступ Balda или агентов ко всем его файлам. Сервис не монтирует целиком Developer или Downloads только потому, что они указаны в конфиге.
Поиск выполняется по имени папки (полное имя или подстрока, без учёта регистра), в выбранном корне либо во всех настроенных корнях. Результат содержит имя корня и относительный путь папки, чтобы различать одинаковые имена. Имена файлов и содержимое файлов в поиск не входят. Выход за корни через .. и символические ссылки не допускается. Подключение найденной папки по-прежнему требует подтверждения владельца точного пути, получателя, прав и срока.
Порядок реализации: загрузить и проверить roots из конфига; реализовать листинг/навигацию; добавить поиск по имени; включить операции в MCP; проверить поиск в нескольких корнях, одинаковые имена, отсутствующий/недоступный корень и запрет выхода за границы.
Границы
SSH-запуск, ACP-транспорт, исполнение команд на хосте и Seatbelt относятся к настройке Balda и среды, а не к Workspace Gateway. Prism, Callee, Beads, управление задачами и сессиями используются штатно. Сервис не реализует собственные Story workflows, собственный Prism и дублирующий scheduler.
Общий каталог Developer и домашний каталог не выдаются агентам.
Листинг папок даёт возможность запросить конкретный путь, а не право читать его файлы.
Ответ от модели или аргумент approved=true не является подтверждением владельца.
Отзыв и истечение срока должны прекращать реальный доступ, включая существующие соединения и открытые файловые дескрипторы.
Конкретные шаги
- Я проверю готовую сетевую файловую систему на текущем Docker/Colima и целевых средах: исходные файлы видны обоим клиентам, добавление разрешённой папки обходится без перезапуска Balda, соседняя папка недоступна, отзыв закрывает уже выданный доступ.
- Я подключу постоянную точку сетевой файловой системы в work dir; это разовая настройка deployment, последующие выдачи и отзывы происходят в рантайме.
- Я реализую конфиг нескольких именованных корней (
developer,downloadsи других), листинг/навигацию и поиск папок по имени внутри этих корней; затем запрос подключения, связав подтверждение владельца с точным путём, получателем, правами и сроком. Сначала проверю пригодность штатных взаимодействий Balda. Приёмка поиска включает несколько корней, одинаковые имена папок, недоступный корень и запрет выхода через ссылки или... - Я реализую отключение и временный лизинг, сохранение состояния разрешений и обработку истечения срока после перезапуска сервиса; неполученное подтверждение оставляет доступ закрытым.
- Я проведу приёмку с двумя клиентами: общие файлы, RO/RW, запрет соседних путей и обхода через ссылки, отказ владельца, отзыв, истечение, продление и повторный запуск сервиса.
Выбран и принят SMB3 backend: native Samba, mount.cifs Colima и mount_smbfs macOS. Приняты оригинальные файлы, RO/RW, динамические grants, отзыв открытых FD, независимый expiry и реальный отзыв после перезапуска Manager. Подробности — в актуальном журнале ниже. До выбора backend сохраняется ровно этот объём; общая копия всех репозиториев и ослабление изоляции не являются заменой выдаче доступа.
Что уже проверено и что остаётся
- Создан отдельный Git-проект с зафиксированной границей четырёх функций.
- Проверена независимая возможность штатного ACP Balda поверх SSH: personal/projects/balda/ssh-acp-verification-2026-10-18.
- Выбрана и испытана сетевая файловая система: native SMB3, Linux и Mac.
- Реализованы четыре функции, native подтверждения, реальный отзыв открытых FD и независимый срок доступа.
- Настроено общее состояние Beads и принята работа реальных агентов через полученный workspace.
Доступ к исходникам и доступ к состоянию Beads — связанные, но отдельные пункты общей установки. Для одновременной работы Balda и нескольких агентов Beads описывает server mode Dolt: официальная архитектура. Сетевой mount сам по себе не считается приёмкой конкурентной работы БД.
Выполнение 2026-10-18 — промежуточный журнал
- Исходники находятся в
/Users/admin/Developer/workspace-gateway: конфиг именованных корней, навигация и поиск только папок; запрет.., выхода через ссылки и выдачи целого корня. - Ровно четыре MCP-инструмента:
workspace_folders,workspace_connect,workspace_disconnect,workspace_lease. Подтверждение через MCP elicitation; путь, получатель, RO/RW и точный срок перечисляются в запросе владельцу. - Написано ядро лизинга: атомарный журнал с fsync, отдельно подтверждаемое продление, видимый отказ отзыва и повторные попытки, закрытие незавершённых/активных разрешений после перезапуска. Это проверено тестовым backend; реальные mounts и отзыв файлового доступа ещё не приняты. В исполняемом сервисе подключение закрыто до выбора проверенного backend.
- В реальном проекте прошли
go test -race ./...,go vet ./..., сборка. Настоящий stdio MCP: initialize, tools/list (4 инструмента), листинг без имён файлов, отказ на traversal и неподтверждённом backend. - HTTP MCP: авторизация проверена локально на Mac,
host.docker.internalразрешён, чужой Host отвергается. Из отдельного контейнера Colima проверены достижимость и HTTP 401 без токена; аутентифицированный MCP из контейнера не проверялся. Рабочий порт для подготовки:17795(7795 занят прежним Broker). - Подготовлены
/private/tmp/workspace-setup-20261018/nfs-admin.pyиnfs-acceptance.py. Полный запуск:sudo /opt/homebrew/bin/python3 /private/tmp/workspace-setup-20261018/nfs-admin.py test. Он предназначен только для fixture/private/tmp/workspace-setup-20261018/nfs/source/allowed, клиентов Colima и восстановления исходного состояния после теста. - Первый ручной
startостановился до изменения системы из-за неверной обработки штатного exit 1 уnfsd status; проверка исправлена на наличие самого процесса nfsd и проверена с mock. Полная NFS-приёмка ещё ожидает ручного sudo. На момент этой записи/etc/exportsотсутствует, nfsd не запущен. - Закрытые отчёты/резервные копии:
/Users/admin/Docker/balda-mm-mac/state/workspace-setup-20261018. Production Balda не переключалась.
NFS: ручной запуск и диагностика сетевого пути
Пользователь выполнил nfs-admin.py start: штатный nfsd реально запущен, RPC NFSv3/2049 и mountd зарегистрированы, showmount -e localhost показывает только fixture. Полный test этим выводом ещё не подтверждён.
Первое подключение обоих контейнеров получило Permission denied. Причина в исходной настройке fixture, не доказательство непригодности NFS: TCP-измерение показало, что Mac видит клиента Colima как 127.0.0.1, тогда как экспорт разрешал 192.168.5.1. Отдельно проверено преобразование reserved port: контейнер привязал исходящий порт 900, на Mac наблюдался 127.0.0.1:64152. Артефакт: /private/tmp/workspace-setup-20261018/nfs/colima-source-address.json.
nfs-admin.py test исправлен: разрешает только fixture для loopback, на время теста учитывает переписывание порта в MOUNT RPC, после проверки восстанавливает исходные байты /etc/nfs.conf, удаляет только собственный экспорт и останавливает тестовый сервер. Логика полного восстановления проверена с mock на успешном и ошибочном пути; реальное RO/RW/открытые FD пока ожидает ручного запуска test с sudo. Отказ обоим клиентам не считается успешной изоляцией получателей: результат теперь null до успешного доступа разрешённого клиента.
NFS: результат полного запуска и установленная причина отказа
Пользователь выполнил полный nfs-admin.py test. Оба клиента завершились на mount с Permission denied, поэтому RO/RW и отзыв FD не проверены. Система после сценария реально восстановлена: /etc/exports отсутствует, nfsd остановлен, /etc/nfs.conf содержит исходный текст.
Дальнейшая диагностика установила блокировку самой операции mount в тестовом клиенте; она не позволяет считать созданным NFS mount, независимо от возможных предварительных RPC: Docker использует AppArmor docker-default; с CAP_SYS_ADMIN обычный mount пустого tmpfs возвращает Permission denied (exit 255). Тот же контроль с apparmor=unconfined только у одноразового fixture-контейнера успешно монтирует tmpfs. Это пропуск в тестовом окружении, а не свидетельство непригодности NFS. Предыдущее объяснение одним адресом Colima было неполным; адрес/порт действительно переписываются, но исходные mount-пробы дополнительно блокировались AppArmor.
Подготовлен минимальный отдельный образ workspace-nfs-client:20261018 с официальным nfs-utils 2.6.4; image ID sha256:5468d8d0555b1658bd7626f0f840269203dac8bde49160261268c03aea8b75f4. Он не содержит пользовательских конфигов, токенов или ключей. Предварительная проверка клиента без Mac sudo реально прошла: стандартный mount.nfs существует, tmpfs монтируется. Исправлены fixture options и fail-fast: при неудачном initial тест больше не прогоняет RO/отзыв на остановленных контейнерах. Восстановление root-сценария снова проверено с mock для успеха и ошибки. Для реальной проверки NFS всё ещё требуется повторный ручной sudo ... nfs-admin.py test.
Принятый SMB backend — 2026-10-18
Финальная реализация закоммичена 00b7e13. Используются готовые Samba SMB3 и штатные клиенты macOS/Colima. На каждый lease выдаётся отдельный server/share с отдельным credential, точным bind только разрешённой папки и RO/RW на сервере. Истечение исполняет сам server supervisor, независимо от процесса Manager. Отзыв удаляет share, reload и close-share закрывают открытые FD, затем снимаются mounts; server ещё 60 секунд отвечает отказом старым клиентам и сам удаляется.
Приняты реальные проверки: динамическое подключение в уже работающий непривилегированный контейнер; чтение/запись оригинала с Linux и Mac; server RO; продление без смены mount; отзыв открытых read/write FD обоих клиентов; истечение без Manager; отказ продлению истёкшего share. Дополнительно Go→встроенный backend и фактический отзыв при перезапуске Manager прошли. Ранний протокольный тест также проверил отказ credentials другого получателя, symlink escape и сохранение другого share при отзыве первого. Сохранённая повторяемая приёмка: tests/smb_acceptance.py; отчёт ~/.local/share/workspace-manager-acceptance/report.json.
Постоянный privileged mount-helper был отклонён автоматической проверкой и исключён. Финальный вариант устанавливает cifs-utils в Colima и выполняет обычные разовые native mount/umount команды; привилегированный Docker daemon/helper не остаётся. Корни Developer/Downloads служат только обнаружению. В recipient монтируется только его mount root /var/lib/workspace-manager/balda, с rslave, по совпадающему абсолютному пути на Mac/в Balda. NFS больше не является зависимостью выбранного backend; повторный ручной sudo тест не требуется.
Сервис установлен на 127.0.0.1:17795, private config/state: ~/.local/share/balda-workspace/workspace; настоящее authenticated MCP initialize/tools/list/folders из доверенного образа Balda прошло. Production конфиг Balda ещё не переключался: candidate и финальная прикладная приёмка отслеживаются в personal/plans/balda-remote-agent.