mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-19 10:56:06 +00:00
docs(tenancy): record verification evidence
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user