Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code f76f4466cb fix(user): add missing userWorkspaceEntity cache invalidation on deletion
https://sonarly.com/issue/26579?type=bug

When a user is removed from a workspace via `UserService.removeUserFromWorkspaceAndPotentiallyDeleteWorkspace()` or `UserWorkspaceService.deleteUserWorkspace()`, the `userWorkspaceEntity` entry in `CoreEntityCacheService` is never invalidated. The JWT authentication layer (`JwtAuthStrategy.resolveUserContext`) reads the stale cached record, so middleware hydration succeeds and passes auth guards. However, the `currentUser` resolver performs a fresh DB query with TypeORM (which filters soft-deleted rows), finds no matching `userWorkspace`, and throws `Error: Current user workspace not found`.

Fix: Added `coreEntityCacheService.invalidate('userWorkspaceEntity', userWorkspaceId)` at the end of `UserWorkspaceService.deleteUserWorkspace()`, after the DB deletion completes.

This is the centralized low-level deletion method called by both:
- `UserService.removeUserFromWorkspaceAndPotentiallyDeleteWorkspace()` (user-leaves-workspace path)
- `WorkspaceService.handleRemoveWorkspaceMember()` (admin-removes-member path)

Previously, only `handleRemoveWorkspaceMember` invalidated the cache (at its own call site in workspace.service.ts:637). By moving invalidation into `deleteUserWorkspace()` itself, ALL deletion paths now correctly invalidate the `userWorkspaceEntity` cache entry.

This prevents the bug where:
1. A userWorkspace record is deleted from the DB
2. `JwtAuthStrategy` reads a stale cached record and allows the request through
3. The `currentUser` resolver queries the DB fresh, finds no matching userWorkspace, and throws "Current user workspace not found"

The existing invalidation in `WorkspaceService.handleRemoveWorkspaceMember()` (line 637-640) becomes redundant but harmless — double-invalidation is a no-op. Removing it would be a separate cleanup concern.
2026-04-15 12:18:09 +00:00
@@ -325,6 +325,11 @@ export class UserWorkspaceService extends TypeOrmQueryService<UserWorkspaceEntit
await this.roleTargetRepository.delete({ userWorkspaceId }); // TODO remove once userWorkspace foreign key is added on roleTarget
await this.userWorkspaceRepository.delete({ id: userWorkspaceId });
}
await this.coreEntityCacheService.invalidate(
'userWorkspaceEntity',
userWorkspaceId,
);
}
async findAvailableWorkspacesByEmail(email: string) {