fix(auth): tenancy-mode-aware create-user bind + ADR-0093 integration tests#2887
Merged
Conversation
… tests Multi-org runtime verification (enterprise @objectstack/organizations linked into a live stack) caught a real gap in the #2884 endpoint bind: it resolved its target org via resolveDefaultOrgId (slug='default' first), so in multi-org — where the bootstrap default org coexists with tenant orgs — /admin/create-user would have bound new users into the default org, violating ADR-0093 D3. The bind now consults the tenancy service (getTenancy endpoint dep): single mode → default org; multi mode → no bind. Two unit regression tests added. Verified live on a clean multi-org stack: mode=multi (multiOrgEnabled=true, degradedTenancy=false), no fail-fast with the plugin loaded, sign-in works, and BOTH create-user and sign-up leave new users member-less (DB-verified) — invites / host hooks own membership there. Single-org behavior unchanged. Also: - export reconcile-membership + tenancy-service from the package index (the ADR-0093 host API: hosts compose the reconciler; embeddings query mode). - dogfood integration tests (packages/dogfood/test/membership-reconciler. dogfood.test.ts) driving the REAL better-auth pipeline: sign-up membership via the user.create.after reconciler alone (the invariant e2e), backfill bind + idempotency (D6), invite-only refusal (D1), yield-to-host-membership (D2). bootStack keeps autoDefaultOrganization:false, so the tests mint the default org themselves (system context). - dogfood gains a workspace dep on @objectstack/plugin-auth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XbLd2KKeVs39EztDYMQ1YU
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2884 (merged). Carries the one real bug found by multi-org runtime verification plus the ADR-0093 integration-test hardening.
The bug (found by verification, fixed here)
The #2884 endpoint bind resolved its target org via
resolveDefaultOrgId— which prefers theslug='default'org regardless of how many orgs exist. In a multi-org deployment the bootstrap Default Organization coexists with real tenant orgs, so/admin/create-userwould have bound every new user into the default org — violating ADR-0093 D3 ("the framework never guesses in multi mode"). Notably this was a case the old #2882 count-heuristic ("exactly one org") would also have hit whenever only the bootstrap org existed yet.Fix: the bind now consults the
tenancyservice (new optionalgetTenancyonAdminUserEndpointDeps, wired inauth-plugin.ts): single mode → default org; multi mode →defaultOrgId()returnsnull→ no bind. Fallback to the old resolution only when tenancy isn't wired (lean embeddings). Two unit regression tests pin it.Multi-org runtime verification (how the bug was caught)
Built
@objectstack/organizationsfrom the cloud repo (itslink:deps pointed at this worktree), linked it into the showcase example, booted withOS_MULTI_ORG_ENABLED=true, and verified on a clean instance:Tenancy: multi-tenant,multiOrgEnabled=true,degradedTenancy=false/admin/create-user→ membershiporganizationId: null) — with this fix; would have mis-bound without itsys_member)(Single-org e2e was verified previously: create-user and sign-up both produce default-org memberships.)
Integration tests (dogfood)
New
packages/dogfood/test/membership-reconciler.dogfood.test.ts— drives the real better-auth pipeline viabootStack(showcase):user.create.afterreconciler alone — the invariant e2e (no endpoint bind exists on this path, so the membership proves the hook).policy-skip+ backfillreason: 'policy', no rows.Harness note:
bootStackdeliberately keepsautoDefaultOrganization: false(the ADR-0057 org-less single-tenant posture) and no better-auth admin plugin, so the tests mint the default org themselves (system context) and the create-user endpoint path stays covered by its 31 unit tests.Also exports
reconcile-membership+tenancy-servicefrom the package index as the ADR-0093 host API, and adds the@objectstack/plugin-authworkspace dep to dogfood.Testing
🤖 Generated with Claude Code
https://claude.ai/code/session_01XbLd2KKeVs39EztDYMQ1YU
Generated by Claude Code