fix(users/organizations/auth): prevent 500 on signin when org deleted without cascade (#3709)#3713
Conversation
…on (#3709) Replace the bare OrganizationsCrudService.removeById call with an inline cascade that properly repairs co-member currentOrganization to their next available org (or null) instead of clearing it uniformly to null.
…pulated org refs (#3709) Filter memberships whose organizationId is null after Mongoose populate (deleted org with dangling ObjectId ref) before dereferencing ._id. Also guard the early-return branch: only trust a membership as still-active when its populated organizationId is non-null.
…3709) Add E2E test verifying signin returns 200 (not 500) when currentOrganization points to a non-existent org ID (pre-existing corruption scenario). Tasks 1+2 already fix the root cause; this test is the belt-and-suspenders regression guard.
|
Warning Review limit reached
More reviews will be available in 13 minutes and 25 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3713 +/- ##
==========================================
+ Coverage 89.73% 89.83% +0.09%
==========================================
Files 143 143
Lines 4794 4800 +6
Branches 1505 1506 +1
==========================================
+ Hits 4302 4312 +10
+ Misses 385 383 -2
+ Partials 107 105 -2
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Fixes a signin crash caused by dangling organization references (memberships populating organizationId: null after an org is hard-deleted), and adds regression coverage around the edge cases that triggered issue #3709.
Changes:
- Harden
autoSetCurrentOrganizationto tolerate null-populatedorganizationIdand avoidnull._iddereferences. - Update
users.service.remove()to perform an inline org-deletion cascade (delete org memberships + repair affected users’currentOrganization) instead of calling the non-cascadingremoveById. - Add E2E + unit regression tests covering deleted-org / bogus-currentOrganization scenarios.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| modules/users/services/users.service.js | Implements cascade org cleanup during user deletion to avoid leaving co-members with dangling currentOrganization. |
| modules/organizations/services/organizations.crud.service.js | Filters out null-populated memberships and tightens early-return logic in autoSetCurrentOrganization. |
| modules/users/tests/users.remove.cascade.e2e.tests.js | New E2E repro test: co-member can still sign in after sole-owner deletion removes org. |
| modules/organizations/tests/organizations.crud.dangling-org.unit.tests.js | New unit tests for autoSetCurrentOrganization null-populate edge cases. |
| modules/auth/tests/auth.e2e.tests.js | New E2E test ensuring signin stays 200 even with corrupted currentOrganization. |
Co-member cascade in `users.service.remove` was dereferencing `remaining[0].organizationId._id` without filtering out null-populated memberships (hard-deleted org), mirroring the same crash fixed in `autoSetCurrentOrganization`. Apply the identical `liveMemberships` filter before picking the next current org. Add unit tests covering the null-only and mixed cases.
Summary
Fixes #3709 —
Cannot read properties of null (reading '_id')500 on signin when a user has an active membership pointing at a deleted organization.Root cause
When a sole-owner user is deleted,
users.service.js:remove()calledOrganizationsCrudService.removeById(orgId)(bare DB delete, no cascade). This left co-members withcurrentOrganizationpointing at the now-deleted org. On the co-member's next signin,autoSetCurrentOrganizationcalledMembershipRepository.list()which populatesorganizationId— Mongoose returnsnullfor deleted orgs — then crashed onnull._id.Three-layer fix
Layer 1 (
users.service.js): Replace the bareremoveByIdcall with an inline cascade that:currentOrganization = orgId(affected users)currentOrganization(or sets null if none)OrganizationsRepository.remove(preserving task data, consistent with previous behavior)Layer 2 (
organizations.crud.service.js): HardenautoSetCurrentOrganization:organizationIdisnullafter Mongoose populate before dereferencing._idorganizationIdis non-nullLayer 3 (
auth.e2e.tests.js): Add regression test verifying signin returns 200 (not 500) whencurrentOrganizationis a bogus ObjectId (pre-existing data-integrity anomaly scenario, belt-and-suspenders).Tests added
modules/users/tests/users.remove.cascade.e2e.tests.js— full repro: User A (sole owner) deleted → Org X removed → User B (co-member) can sign in without 500modules/organizations/tests/organizations.crud.dangling-org.unit.tests.js— 4 unit tests covering all null-populate edge cases inautoSetCurrentOrganizationmodules/auth/tests/auth.e2e.tests.js— 1 new test: data-integrity corruption → signin still 200Test results