diff --git a/docs/multi-tenant/implementation-checklist.md b/docs/multi-tenant/implementation-checklist.md index d73fb022b..fdb9c8fd7 100644 --- a/docs/multi-tenant/implementation-checklist.md +++ b/docs/multi-tenant/implementation-checklist.md @@ -1,6 +1,8 @@ # Multi-tenant implementation checklist -This checklist turns the Workspace architecture into implementation and verification gates. +This checklist turns the Workspace architecture into implementation and +verification gates. Exact commands and observed results are recorded in the +[verification report](./verification-report.md). ## Scope guard diff --git a/docs/multi-tenant/verification-report.md b/docs/multi-tenant/verification-report.md new file mode 100644 index 000000000..307e54a6b --- /dev/null +++ b/docs/multi-tenant/verification-report.md @@ -0,0 +1,164 @@ +# Multi-tenant verification report + +Date: 2026-07-19 + +This report records the implementation and verification evidence for the Core +Workspace isolation kernel. It does not claim that the closed SaaS Control +Plane or Cloud v2 deployment is production-ready. + +## Repository refs and scope + +- LangBot branch: `feat/multi-tenants` +- LangBot implementation commit: `c6f826fe2d2e12cc73479155e8f25566048c1c56` +- LangBot base: `origin/master` at + `6baeb032a7f76c65337b51c7b58593de4687a61c` +- Plugin SDK branch: `feat/multi-tenants` +- Plugin SDK commit and LangBot dependency pin: + `a1544b6b38a37ba72e3284f2836618144f0742c1` +- Space remained on `main` at + `5058b039c2629e3b01ebd7358369b50e7df62a1c`, with no tracked changes made by + this implementation. + +The SDK protocol is versioned as 0.4.15 but is intentionally consumed from the +exact pushed Git commit on this feature branch. Publishing 0.4.15 and replacing +the Git pin with a registry pin remain merge-to-master release steps. + +## Automated verification + +### LangBot backend + +```text +.venv/bin/ruff check . + passed + +changed and untracked Python format check + 220 files already formatted + +.venv/bin/pytest tests/unit_tests -q + 2051 passed, 1 skipped, 110 warnings in 26.87s + +.venv/bin/pytest tests/integration -q + 163 passed, 19 skipped, 28 warnings in 6.00s + +uvx --from uv@latest uv lock --check + resolved 277 packages; passed + +git diff --check + passed +``` + +### Database migrations + +- Fresh and upgraded SQLite schemas passed, including verified pre-boundary + backups, forced-failure restore, retry, and revision manifest checks. +- A disposable PostgreSQL 16 instance exercised fresh and upgraded tenancy + migrations: `9 passed, 9 warnings in 8.57s`. +- Alembic has one head, `0010_scope_resources`, through the chain + `0008_mcp_resource_prefs -> 0009_workspace_tenancy -> + 0010_scope_resources`. +- ORM-to-migration coverage found no missing tenant table. + +### Plugin SDK and runtime + +```text +SDK full test suite + 1029 passed, 18 warnings in 8.20s + +SDK Ruff and action consistency checks + passed + +Docker-backed Box integration tests + 13 passed +``` + +The SDK remote branch and LangBot Git dependency were both resolved and +verified at the same commit recorded above. + +### Frontend + +```text +pnpm lint + 0 errors, 34 warnings + +pnpm build + passed; 3167 modules + +pnpm exec playwright test --project=chromium + 40 passed in 19.9s + +Bot form initialization race pressure test + 10 passed in 9.4s +``` + +The browser suite covers singleton bootstrap, explicit multi-Workspace +selection under the test policy, selector headers, account-state cleanup, +Workspace switching, and invitation terminal-state recovery. + +### Packaging and deployment configuration + +- Docker Compose with Plugin Runtime and Box control tokens passed + `docker compose ... --profile all config --quiet`. +- Compose, Kubernetes, and the default configuration passed YAML parsing. +- Kubernetes selector, volume, and control-token reference checks passed. +- `skills/bin/lbs index --check` and `skills/bin/lbs validate` passed. +- The staged secret scan found no committed credential; test-token literals + were confirmed to be non-secret fixtures. + +## Real browser E2E + +The bundled production web application and backend were started against a +clean, temporary SQLite data directory. The following flows were performed in +the in-app browser against the real API rather than mocks: + +1. The first Account registered and became owner of the automatically created + singleton Workspace. +2. The owner created a one-time invitation link. +3. A signed-out second Account inspected the fragment-based invitation, + registered, accepted it, and entered the Workspace as viewer. +4. The same member was cycled through viewer, operator, developer, admin, and + owner. Visible controls matched the backend permission matrix, including + owner transfer only for an owner. +5. A viewer invitation mutation returned 403 `permission_denied`; an owner + attempt to create a second OSS Workspace returned 403 `edition_limit`. +6. Owner/member account switching, refresh, and a newly opened browser tab + recovered only the active Account and singleton Workspace state. +7. Used, revoked, expired, and email-mismatched invitation states rendered + distinct errors. Terminal tokens were cleared, while the mismatch flow + allowed switching to the intended Account. +8. With the plugin system disabled, `/api/v1/plugins` and + `/api/v1/system/status/plugin-system` both returned 200 after a clean server + restart. The only remaining browser console error was the expected failure + to reach the optional external Space release feed. + +The test server was stopped, port 15321 was verified free, and the temporary +test directory was moved to the system Trash. Multi-Workspace same-name and +same-identifier isolation is exercised by the automated test-only Cloud policy; +the OSS browser cannot create a second Workspace by design. + +## Final audit + +The final isolation audit found no remaining P0/P1 tenant isolation issue in +the OSS singleton-Workspace, multi-user scope. Focused checks also covered the +plugin-disabled Workspace fence, invitation fragment/account-switch behavior, +and the Bot form initialization sequence. Unrelated untracked workspace files +were excluded from both commits. + +## Deliberately incomplete SaaS gates + +Multi-Workspace activation remains unavailable in the open-source bootstrap. +Cloud v2 must remain disabled until the following closed-system gates are +implemented and independently verified: + +- signed `InstanceManifest` verification and closed `CloudWorkspacePolicy` + injection; +- authoritative Account, Workspace, Membership, Invitation, placement, + entitlement, usage, subscription, and billing services; +- generation-aware database transaction and outbox fences through commit; +- stable durable object references across placement-generation cutovers; +- atomic shared OAuth-state and directory-projection stores; +- tenant-safe egress and SSRF enforcement for all configurable outbound URLs; +- a greenfield Cloud v2 deployment, without carrying forward the legacy Space + deployment model. + +These are release gates, not hidden fallbacks. Mutable Core configuration or an +edition flag cannot enable SaaS multi-tenancy.