Files
obsidian-vault/personal/plans/workspace-gateway.md
T

111 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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]].