111 lines
21 KiB
Markdown
111 lines
21 KiB
Markdown
# Workspace Gateway — план
|
||
|
||
Обновлено: **2026-10-18**.
|
||
Проект: `/Users/admin/Developer/workspace-gateway`.
|
||
Git: `main`, реализация `00b7e13`; актуальные deployment scripts и приёмка `e99f043` (2026-10-18). Четыре MCP-функции реализованы; принят native SMB3 backend с фактическим отзывом открытых FD на Linux и Mac, независимым истечением срока и динамическим подключением без рестарта получателя. Сервис установлен как user launchd job на `127.0.0.1:17795`; аутентифицированные вызовы из доверенного образа Balda прошли. Переключение production Balda и полная прикладная приёмка ещё не завершены.
|
||
Общий setup Balda: [[personal/plans/balda-remote-agent]].
|
||
|
||
## Назначение и четыре функции
|
||
|
||
Сервис выдаёт Balda и удалённым агентам доступ к исходным папкам через сетевую файловую систему.
|
||
Balda и агенты видят одни и те же файлы; копирование Git-репозитория не считается реализацией общего доступа.
|
||
|
||
1. **Папки:** листинг и навигация по папкам внутри настроенных корней (`developer`, `downloads` и других), а также поиск папок по имени; без выдачи списка файлов и их содержимого.
|
||
2. **Подключение:** выбранная папка появляется в work dir после подтверждения владельцем точного пути, получателя, режима доступа и срока.
|
||
3. **Отключение:** фактический отзыв ранее выданного доступа.
|
||
4. **Лизинг:** статус и срок действия, автоматический отзыв после истечения срока, продление с подтверждением владельца.
|
||
|
||
Четыре пользовательские функции — согласованный объём проекта.
|
||
Обработка ответа владельца, журнал выданных разрешений и таймеры обслуживают эти функции, а не расширяют API прикладными сценариями.
|
||
|
||
## Конфиг корней и поиск папок
|
||
|
||
Workspace Manager — пользовательское название сервиса; текущие путь проекта и имя этой заметки остаются `workspace-gateway`.
|
||
|
||
В конфиге задаются несколько именованных корней; список расширяется без изменения кода. Например:
|
||
|
||
```yaml
|
||
roots:
|
||
developer: /Users/admin/Developer
|
||
downloads: /Users/admin/Downloads
|
||
```
|
||
|
||
Корень задаёт область обнаружения папок, а не автоматический доступ Balda или агентов ко всем его файлам. Сервис не монтирует целиком `Developer` или `Downloads` только потому, что они указаны в конфиге.
|
||
|
||
Поиск выполняется по имени папки (полное имя или подстрока, без учёта регистра), в выбранном корне либо во всех настроенных корнях. Результат содержит имя корня и относительный путь папки, чтобы различать одинаковые имена. Имена файлов и содержимое файлов в поиск не входят. Выход за корни через `..` и символические ссылки не допускается. Подключение найденной папки по-прежнему требует подтверждения владельца точного пути, получателя, прав и срока.
|
||
|
||
Порядок реализации: загрузить и проверить `roots` из конфига; реализовать листинг/навигацию; добавить поиск по имени; включить операции в MCP; проверить поиск в нескольких корнях, одинаковые имена, отсутствующий/недоступный корень и запрет выхода за границы.
|
||
|
||
## Границы
|
||
|
||
SSH-запуск, ACP-транспорт, исполнение команд на хосте и Seatbelt относятся к настройке Balda и среды, а не к Workspace Gateway.
|
||
Prism, Callee, Beads, управление задачами и сессиями используются штатно.
|
||
Сервис не реализует собственные Story workflows, собственный Prism и дублирующий scheduler.
|
||
|
||
Общий каталог Developer и домашний каталог не выдаются агентам.
|
||
Листинг папок даёт возможность запросить конкретный путь, а не право читать его файлы.
|
||
Ответ от модели или аргумент `approved=true` не является подтверждением владельца.
|
||
Отзыв и истечение срока должны прекращать реальный доступ, включая существующие соединения и открытые файловые дескрипторы.
|
||
|
||
## Конкретные шаги
|
||
|
||
1. Я проверю готовую сетевую файловую систему на текущем Docker/Colima и целевых средах: исходные файлы видны обоим клиентам, добавление разрешённой папки обходится без перезапуска Balda, соседняя папка недоступна, отзыв закрывает уже выданный доступ.
|
||
2. Я подключу постоянную точку сетевой файловой системы в work dir; это разовая настройка deployment, последующие выдачи и отзывы происходят в рантайме.
|
||
3. Я реализую конфиг нескольких именованных корней (`developer`, `downloads` и других), листинг/навигацию и поиск папок по имени внутри этих корней; затем запрос подключения, связав подтверждение владельца с точным путём, получателем, правами и сроком. Сначала проверю пригодность штатных взаимодействий Balda. Приёмка поиска включает несколько корней, одинаковые имена папок, недоступный корень и запрет выхода через ссылки или `..`.
|
||
4. Я реализую отключение и временный лизинг, сохранение состояния разрешений и обработку истечения срока после перезапуска сервиса; неполученное подтверждение оставляет доступ закрытым.
|
||
5. Я проведу приёмку с двумя клиентами: общие файлы, RO/RW, запрет соседних путей и обхода через ссылки, отказ владельца, отзыв, истечение, продление и повторный запуск сервиса.
|
||
|
||
Выбран и принят SMB3 backend: native Samba, mount.cifs Colima и mount_smbfs macOS. Приняты оригинальные файлы, RO/RW, динамические grants, отзыв открытых FD, независимый expiry и реальный отзыв после перезапуска Manager. Подробности — в актуальном журнале ниже.
|
||
До выбора backend сохраняется ровно этот объём; общая копия всех репозиториев и ослабление изоляции не являются заменой выдаче доступа.
|
||
|
||
## Что уже проверено и что остаётся
|
||
|
||
- [x] Создан отдельный Git-проект с зафиксированной границей четырёх функций.
|
||
- [x] Проверена независимая возможность штатного ACP Balda поверх SSH: [[personal/projects/balda/ssh-acp-verification-2026-10-18]].
|
||
- [x] Выбрана и испытана сетевая файловая система: native SMB3, Linux и Mac.
|
||
- [x] Реализованы четыре функции, native подтверждения, реальный отзыв открытых FD и независимый срок доступа.
|
||
- [ ] Настроено общее состояние Beads и принята работа реальных агентов через полученный workspace.
|
||
|
||
Доступ к исходникам и доступ к состоянию Beads — связанные, но отдельные пункты общей установки.
|
||
Для одновременной работы Balda и нескольких агентов Beads описывает server mode Dolt: [официальная архитектура](https://github.com/gastownhall/beads/blob/main/docs/architecture/index.md).
|
||
Сетевой 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]].
|