Skip to content

Commit 24bbd0b

Browse files
chore(examples): declare @objectstack/organizations in the showcase so a walled os serve boots without a temporary edit (#25418)
<!-- claude-projects-attribution: {"github_login":"os-sales"} --> _Requested by **Sales** · [project thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuDWJsBGQpadCH8JR2xZQ5re)_ Fixes #25365 Clause-②: no ## What changed - `examples/app-showcase/package.json` declares `@objectstack/organizations` (`workspace:*`, the open Apache-2.0 build, ADR-0132 D3: the host manifest decides which build of the name a deployment gets). The card's option (a). - `pnpm-lock.yaml`: the one importer link that declaration adds (+3 lines, no other churn). - `examples/app-showcase/README.md`: a "Booting it walled" section naming the env a production walled `os serve` needs. The showcase is `private: true`, so nothing publishes: `skip-changeset`. ## Mechanism, measured on `origin/main` 830a63a - `packages/cli/src/commands/serve.ts`: `multiTenant = tenancyPosture !== 'single'`; only then is `@objectstack/organizations` imported, through `importFromHost` (resolved from the served app's own `node_modules`). Import failure under a walled posture exits 1 unless `OS_ALLOW_DEGRADED_TENANCY`. Under `single` the import is never reached. All three premises hold. ## Boot readings (head 0cc7b77, `NODE_ENV=production`, fresh database each run, `OS_CLOUD_URL=off`) Common env: `OS_AUTH_SECRET`, `OS_SECRET_KEY`, `OS_DATABASE_URL=file:./.objectstack/data/app.db`; walled runs add `OS_PLATFORM_OWNER_EMAIL` and `OS_AUTH_MEMBERSHIP_POLICY=invite-only`. | run | result | decisive line | |---|---|---| | `single`, dependency declared | ready, exit 0 on SIGTERM | `Tenancy: single`, `Plugins: 50 loaded`, no `Organizations`; `/auth/config` `multiOrgEnabled:false` | | `single`, control: package link removed from the showcase's `node_modules` | ready, exit 0 | `Plugins: 50 loaded`; plugin list byte-identical (same md5) to the row above | | `isolated`, README recipe verbatim (`pnpm exec objectstack serve`) | ready | `Tenancy: isolated`, `Plugins: 51 loaded`, `Organizations` in the list; `/auth/config` `degradedTenancy:false` | | `group`, README recipe verbatim | ready | `Tenancy: group`, `Plugins: 51 loaded`, `Organizations`; `degradedTenancy:false` | | `isolated`, control: package link removed | exit 1 | `FATAL: tenancy posture 'isolated' was requested but @objectstack/organizations could not be loaded` | | `isolated`, no membership policy | exit 1 | `FATAL: tenancy posture 'isolated' is walled, but this deployment never declared a membership policy` (the organizations plugin's own gate: the package loaded) | | `isolated`, no `OS_SECRET_KEY` | exit 1 | `[LocalCryptoProvider] Refusing to start in production without a stable encryption key` | | `isolated`, no `OS_PLATFORM_OWNER_EMAIL` | exit 1 | `tenancy posture 'isolated' requires OS_PLATFORM_OWNER_EMAIL to be set` | The last three rows are why each variable is in the README recipe. Every other example is untouched, so its `single` boot is unchanged by construction. ## Gates (local, head 0cc7b77) - `node scripts/pm/dispatch-gates.mjs --commands`: 47 commands; 46 exit 0, `pnpm check:dual-build-cjs-loads` exit 3 (PREREQUISITE NOT MET: needs a full build) = NOT MEASURED locally, CI runs it. `--ran` reconciliation: 47 derived, 46 run, 1 NOT-MEASURED, 0 UNRUN. - `pnpm --filter @objectstack/example-showcase run typecheck && … run test`: VERDICT command-exit 0, Test Files 37/37, Tests 443/443. - `pnpm lint`: VERDICT command-exit 0. ## Acceptance notes - A walled boot of the showcase logs a non-fatal `WARN [security] audience-binding suggestion sync failed` (no organization with slug `default` and more than one organization, so the deployment-level acceptance must come from the security plugin's `acceptedDefaultPermissionSets`). Observation only; the boot is green and this card does not change it. - The card's third temporary setting (an audience posture with self-registration, for a self-registering tenant) is not needed to boot and is not in the recipe; this PR measured boot only. --- _Generated by [Claude Code](https://claude.ai/code/session_01CxBKycaiUpA1yGx1XyoGqX)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4e606ce commit 24bbd0b

3 files changed

Lines changed: 30 additions & 0 deletions

File tree

‎examples/app-showcase/README.md‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@ pnpm dev # → http://localhost:3000/_studio
4040
pnpm verify
4141
```
4242

43+
### Booting it walled (`isolated` / `group`)
44+
45+
The showcase declares `@objectstack/organizations` (the Apache-2.0 multi-organization
46+
runtime, app-declared per ADR-0132 D3). `os serve` loads it only when
47+
`OS_TENANCY_POSTURE` is `isolated` or `group`; under `single`, the default, it is never
48+
loaded and the boot is unchanged. A production walled boot needs this env, with no edit
49+
to the app:
50+
51+
```bash
52+
pnpm --filter '@objectstack/example-showcase^...' build # once
53+
cd examples/app-showcase
54+
NODE_ENV=production \
55+
OS_TENANCY_POSTURE=isolated \
56+
OS_AUTH_SECRET=$(openssl rand -hex 32) \
57+
OS_SECRET_KEY=$(openssl rand -hex 32) \
58+
OS_DATABASE_URL=file:./.objectstack/data/app.db \
59+
OS_PLATFORM_OWNER_EMAIL=owner@example.com \
60+
OS_AUTH_MEMBERSHIP_POLICY=invite-only \
61+
pnpm exec objectstack serve -p 3000
62+
```
63+
64+
Each variable answers one boot refusal: the auth secret, the encryption key, the
65+
storage, the platform owner (a walled posture never promotes the first sign-up), and a
66+
declared membership policy (`invite-only` or an explicit `auto`). Keep both secrets
67+
stable across restarts of the same database.
68+
4369
## What it covers
4470

4571
### Data layer (ObjectQL)

‎examples/app-showcase/package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"@objectstack/connector-rest": "workspace:*",
3131
"@objectstack/connector-slack": "workspace:*",
3232
"@objectstack/driver-sql": "workspace:*",
33+
"@objectstack/organizations": "workspace:*",
3334
"@objectstack/runtime": "workspace:*",
3435
"@objectstack/service-datasource": "workspace:*",
3536
"@objectstack/service-i18n": "workspace:*",

‎pnpm-lock.yaml‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)