Repository navigation
Commit 149153c
fix(plugin-auth): settle membership under the auto policy at user creation (ADR-0093 D7) (#21813)
Fixes #21791
Clause-②: yes (widening)
## What
Under the `auto` membership policy, membership is now decided when the
user is created (ADR-0093 D7), per the maintainer ruling recorded on the
card. Packages: `@objectstack/plugin-auth`,
`@objectstack/organizations`, `@objectstack/types`.
- **Creation.** User creation binds a new user to the default
organization, as before, and the first session minted by that same
request carries it. The request recognises its own new user from the
store adapter's create result, staged per request context; nothing is
read back, and nothing outlives the request. Later sign-ins do not
decide membership.
- **One-time decisions, recorded in the `sys_migration` ledger.**
- The backfill of users who predate the policy
(`adr-0093-membership-backfill`) scans the user and member tables in
full with keyset pages, with no row cap. An incomplete scan binds nobody
and records nothing. A multi-org deployment with no default target is
recorded as such. A deployment with no organization at all defers, and
the pass runs when the default organization is first created.
- The default-organization owner bind
(`adr-0093-default-org-owner-bind`) runs once. One shared gate
(`createEnsureDefaultOrganizationOnce`) is used by both the
single-organization wiring and the walled `@objectstack/organizations`
wiring. Once decided, a missing default organization is recreated with
nobody bound and no seed-ownership handoff. On a kernel without the
ledger, the owner is bound only when the bootstrap creates the
organization; if the ledger exists but cannot be read, that call binds
nobody and the next trigger decides.
- Each decision is latched in-process once acted on, even if writing its
record fails (that failure is logged at `error`).
- **`keysetWalk` (`@objectstack/types`)** detects a stalled cursor by
key equality or a repeated page, never by string order.
- **Showcase.** The approval-demo seed writes its demo personas'
membership when it creates them.
- **New public surface of `@objectstack/plugin-auth` (additive,
`minor`):** `createEnsureDefaultOrganizationOnce` and
`EnsureDefaultOrganizationOnceOptions`;
`ObjectQLAdapterFactoryOptions.onRecordCreated` via the new optional
second argument of `createObjectQLAdapterFactory`; `bindOnlyOnCreate` /
`bindOwner` on `EnsureDefaultOrganizationOptions`; reason members
`'owner_bind_decided'` and `'scan-incomplete'`.
`@objectstack/organizations` and `@objectstack/types` add no public
export (`patch`).
- **Deprecated, not removed:** the ungated `ensureDefaultOrganization`
(plugin-auth helper and the organizations wrapper), in favour of the
gated factory.
- **Recovery:** after a default organization is recreated with nobody
bound, an administrator re-adds members, including themselves, through
member management.
- **Unchanged.** `invite-only` binds nobody; multi-org has no automatic
binding; the creation paths (sign-up, admin create, import, SSO JIT)
still bind under `auto`.
- **Derived artefacts,** regenerated with their tools: the tenant-audit
census (one new engine write site) with its prose figures, the engine
test-double ledger, the durability gate vocabulary
(`persistLedgerDecisionRow`) and its swallow-census copy.
## Tests
Measured at `3ed15b1836`:
- `@objectstack/plugin-auth`: typecheck green; 121 files, 2541 passed,
10 skipped.
- `@objectstack/organizations`: typecheck green; 9 files, 131 passed.
- `@objectstack/types`: typecheck green; 23 files, 706 passed
(`--project local`).
- Dogfood (real showcase boot): membership decided at creation; demo
personas hold an organization; neighbouring persona, approval-override
and membership-revoke suites — 5 files, 10 passed.
- New coverage: the one-time ledger (first pass, recorded verdict,
multi-org refusal, deferral, pagination past one page, incomplete scan,
unreadable ledger, failed record then later triggers), creation
recognised only within its own request (including a different
pre-existing user in a creating request), restart after a membership
change, the walled owner-bind gate, recreate-without-bind, and keyset
stall detection under non-JS collations.
- Ablations through `scripts/ablation-replace.mjs`, each restored to
HEAD: the request-scoped creation check, the in-process latches (owner
bind, backfill), the keyset equality check, and the persona membership
write each turned their test red.
- `pnpm` gates via `dispatch-gates`: 121 derived, 121 run, all exit 0
(including the changeset gates against `origin/main`); CI-environment
jobs (shards, test completeness, workspace type-check lanes) left to CI.
## Acceptance notes
- **Upgrade boot.** The first boot of this version has no record, so
both one-time passes run once; after that they are recorded.
- **Users inserted directly through the data engine** (including seeds
that finish after their budget) never cross user creation and stay
unbound once the backfill is recorded. Seeds should create users through
the creation seam or write membership themselves, as the showcase seed
now does.
- **ADR-0093 D6's text** still describes the recurring `app:seeded`
re-run; amending it is a governed (Tier H) edit left to the maintainer.
---
_Generated by [Claude
Code](https://claude.ai/code/session_018zT8d8NpiQ1ExhuNd5TxY6)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 88a39c0 commit 149153c
28 files changed
Lines changed: 1678 additions & 96 deletions
File tree
- .changeset
- content/docs/permissions
- docs/audits
- examples/app-showcase/src/security
- packages
- plugins
- organizations/src
- plugin-auth/src
- qa/dogfood/test
- types/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
| 190 | + | |
191 | 191 | | |
192 | | - | |
193 | | - | |
| 192 | + | |
| 193 | + | |
194 | 194 | | |
195 | 195 | | |
196 | 196 | | |
| |||
207 | 207 | | |
208 | 208 | | |
209 | 209 | | |
210 | | - | |
| 210 | + | |
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
214 | | - | |
| 214 | + | |
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
| |||
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
226 | | - | |
| 226 | + | |
227 | 227 | | |
228 | | - | |
| 228 | + | |
229 | 229 | | |
230 | 230 | | |
231 | | - | |
| 231 | + | |
232 | 232 | | |
233 | 233 | | |
234 | 234 | | |
235 | 235 | | |
236 | | - | |
| 236 | + | |
237 | 237 | | |
238 | 238 | | |
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
242 | | - | |
| 242 | + | |
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
246 | 246 | | |
247 | 247 | | |
248 | 248 | | |
249 | 249 | | |
250 | | - | |
| 250 | + | |
251 | 251 | | |
252 | 252 | | |
253 | 253 | | |
| |||
297 | 297 | | |
298 | 298 | | |
299 | 299 | | |
300 | | - | |
| 300 | + | |
301 | 301 | | |
302 | 302 | | |
303 | 303 | | |
304 | | - | |
305 | | - | |
| 304 | + | |
| 305 | + | |
306 | 306 | | |
307 | | - | |
| 307 | + | |
308 | 308 | | |
309 | 309 | | |
Lines changed: 9 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | | - | |
| 36 | + | |
37 | 37 | | |
38 | | - | |
| 38 | + | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
| 41 | + | |
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
| |||
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
93 | | - | |
| 93 | + | |
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
97 | | - | |
98 | | - | |
| 97 | + | |
| 98 | + | |
99 | 99 | | |
100 | | - | |
| 100 | + | |
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
| 138 | + | |
138 | 139 | | |
139 | 140 | | |
140 | 141 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
235 | 235 | | |
236 | 236 | | |
237 | 237 | | |
| 238 | + | |
238 | 239 | | |
239 | 240 | | |
240 | 241 | | |
| |||
246 | 247 | | |
247 | 248 | | |
248 | 249 | | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
249 | 256 | | |
250 | 257 | | |
251 | 258 | | |
| |||
260 | 267 | | |
261 | 268 | | |
262 | 269 | | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
263 | 288 | | |
264 | 289 | | |
265 | 290 | | |
| |||
350 | 375 | | |
351 | 376 | | |
352 | 377 | | |
353 | | - | |
| 378 | + | |
354 | 379 | | |
355 | 380 | | |
356 | 381 | | |
357 | | - | |
| 382 | + | |
358 | 383 | | |
359 | 384 | | |
360 | 385 | | |
| |||
Lines changed: 13 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
4 | | - | |
| 4 | + | |
| 5 | + | |
5 | 6 | | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
13 | | - | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
14 | 12 | | |
15 | 13 | | |
16 | 14 | | |
| |||
32 | 30 | | |
33 | 31 | | |
34 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
35 | 39 | | |
36 | 40 | | |
37 | 41 | | |
| |||
Lines changed: 12 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
| 6 | + | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
468 | 468 | | |
469 | 469 | | |
470 | 470 | | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
471 | 480 | | |
472 | 481 | | |
473 | | - | |
| 482 | + | |
474 | 483 | | |
475 | 484 | | |
476 | 485 | | |
| |||
0 commit comments