You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 33a423d
Browse filesBrowse the repository at this point in the historyBrowse files
`MongoDBDriver` has NO row-level tenant isolation: it never reads
`DriverOptions.tenantId`, so reads carry no tenant predicate and writes are
never stamped with a tenant column. The layer the SQL driver has
(`resolveTenantField` + `applyTenantScope`) does not exist here, while
everything above the driver — the object metadata `tenancy` block,
`applySystemFields` injecting `organization_id`, the engine threading
`tenantId` into every driver call — runs on the assumption that tenant
isolation is a platform guarantee. Point a multi-tenant deployment's
datasource at Mongo and every query read, updated and deleted OTHER tenants'
documents, silently.
This is option B of #3724: rather than gamble that Mongo multi-tenancy is
really wanted, declare the driver single-tenant and fail fast.
- `assertSingleTenantPosture()` refuses any tenancy posture other than
`single` — `OS_TENANCY_POSTURE=group|isolated`, including the posture
derived from `OS_MULTI_ORG_ENABLED=true` — resolved through the shared
`resolveTenancyPosture()` (ADR-0105 D1) so the driver can never disagree
with auth / the registry / the CLI about the mode.
- It runs in the **constructor**, not only in `connect()`, because
`ObjectQLEngine.init()` catches a driver's connect rejection and boots
anyway ("may recover via lazy reconnection"). A connect-only guard would
have degraded "refuses to start" into "starts, then throws at query
time". `connect()` re-checks in case a host flips the posture in between.
- `assertObjectsNotTenantScoped()` refuses objects declaring
`tenancy.enabled: true` at `syncSchema` / `syncSchemasBatch`, naming
every offender in one message.
Both throw `MongoDBMultiTenantUnsupportedError` with
`code === 'MONGODB_MULTI_TENANT_UNSUPPORTED'`; the message names the detected
signal, the remedy, and `@objectstack/driver-sql` as the multi-tenant option.
`serve.ts` swallowed every driver-registration error except
`UnsupportedDriverError`, which would have buried this one and booted with no
driver at all — it now re-throws the coded error too (duck-typed by `code`,
so the CLI keeps no dependency on the driver package) and exits 1.
There is deliberately NO override env var: an escape hatch would restore
exactly the silent non-isolation this removes. Single-tenant deployments —
every currently-working Mongo deployment — are untouched; the real-Mongo
integration suite passes unchanged.
Also closes the loop on the `unique` index comment left by #3717: a
single-field unique index is now correct by construction here, not by
omission.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Hk4hSCirLNWLkgkNkj8YT
> All SQL flavours (PostgreSQL / MySQL / SQLite) are served by a single
@@ -139,6 +139,28 @@ The CLI infers the MongoDB driver from the `mongodb://` (or `mongodb+srv://`)
139
139
URL scheme automatically — no `OS_DATABASE_DRIVER` needed. Set
140
140
`OS_DATABASE_DRIVER=mongodb` only if you want to be explicit.
141
141
142
+
### Multi-tenancy: not supported
143
+
144
+
<Callouttype="warn">
145
+
The MongoDB driver is **single-tenant only**. It implements no row-level tenant
146
+
isolation — unlike `SqlDriver`, it ignores `DriverOptions.tenantId`, so reads
147
+
carry no tenant predicate and writes are not stamped with a tenant column.
148
+
</Callout>
149
+
150
+
Rather than serve a multi-tenant deployment without isolation, the driver
151
+
**refuses to start** in one ([#3724](https://github.com/objectstack-ai/objectstack/issues/3724)):
152
+
153
+
| Signal | Checked in | Result |
154
+
| :--- | :--- | :--- |
155
+
| Tenancy posture is not `single` — `OS_TENANCY_POSTURE=group`/`isolated`, or derived from `OS_MULTI_ORG_ENABLED=true`|`new MongoDBDriver()`, re-checked in `connect()`| throws `MongoDBMultiTenantUnsupportedError`; `objectstack serve` exits 1 |
156
+
| An object declares `tenancy.enabled: true`|`syncSchema()` / `syncSchemasBatch()`| throws, naming every offending object |
157
+
158
+
The error carries `code === 'MONGODB_MULTI_TENANT_UNSUPPORTED'`. There is no
159
+
override flag — one would restore exactly the silent cross-tenant access the
160
+
guard prevents. For multi-tenant deployments use `@objectstack/driver-sql`
161
+
(PostgreSQL / MySQL / SQLite), which enforces tenant scoping at the driver
162
+
level.
163
+
142
164
## SQLite (via `@objectstack/driver-sql`)
143
165
144
166
SQLite is ideal for local-first development and embedded applications.
Copy file name to clipboardExpand all lines: content/docs/deployment/self-hosting.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,7 +32,7 @@ workable default:
32
32
33
33
| Variable | Why it must be set |
34
34
|:---|:---|
35
-
|`OS_DATABASE_URL`| Without it, data lands in a SQLite file under the ObjectStack home directory (`~/.objectstack`, or `<cwd>/.objectstack` next to a project config) — fine for one box, wrong for containers. Use `postgres://…`, `mongodb://…`, or a mounted `file:…` path (`libsql://` / Turso is **not** supported by the open framework — that driver ships in ObjectStack Cloud). |
35
+
|`OS_DATABASE_URL`| Without it, data lands in a SQLite file under the ObjectStack home directory (`~/.objectstack`, or `<cwd>/.objectstack` next to a project config) — fine for one box, wrong for containers. Use `postgres://…`, `mongodb://…`, or a mounted `file:…` path (`libsql://` / Turso is **not** supported by the open framework — that driver ships in ObjectStack Cloud). `mongodb://…` is **single-tenant only**: the MongoDB driver has no row-level tenant isolation and refuses to boot unless the tenancy posture is `single` — see [Drivers → Multi-tenancy](/docs/data-modeling/drivers#multi-tenancy-not-supported). |
36
36
|`OS_AUTH_SECRET`| Session secret for the auth plugin (`AUTH_SECRET` is the legacy alias). Without it, `/api/v1/auth/*` is **silently skipped** — the server runs unauthenticated. |
37
37
|`OS_SECRET_KEY`| 32-byte master key encrypting every stored secret (`openssl rand -hex 32`). On a container's ephemeral filesystem the auto-minted key is **lost on restart**, making previously-encrypted secrets undecryptable. |
38
38
|`OS_PORT`|`os start`**fails loudly** if the port is busy (it never auto-shifts like `os dev`). Pin it and keep your reverse-proxy upstream in sync. |
| Tenancy posture is not `single` — `OS_TENANCY_POSTURE=group\|isolated`, or derived from `OS_MULTI_ORG_ENABLED=true`|`new MongoDBDriver()`, re-checked in `connect()` before a socket is opened | throws `MongoDBMultiTenantUnsupportedError`|
95
+
| An object declares `tenancy.enabled: true`|`syncSchema()` / `syncSchemasBatch()`| throws, naming every offending object |
96
+
97
+
The error carries `code === 'MONGODB_MULTI_TENANT_UNSUPPORTED'` so a host can
98
+
recognise it without matching on the message:
99
+
100
+
```typescript
101
+
import {
102
+
MongoDBMultiTenantUnsupportedError,
103
+
MULTI_TENANT_UNSUPPORTED_CODE,
104
+
} from'@objectstack/driver-mongodb';
105
+
```
106
+
107
+
There is deliberately **no override flag** — one would restore exactly the
108
+
silent cross-tenant access the guard exists to prevent. To run MongoDB, keep the
109
+
deployment single-tenant (`OS_TENANCY_POSTURE=single` or unset, `OS_MULTI_ORG_ENABLED`
110
+
unset or `false`, no object declaring `tenancy.enabled: true`); to go
111
+
multi-tenant, switch to `@objectstack/driver-sql`.
0 commit comments