1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-27 13:49:10 +02:00

fix: audit scim user deleted events (#10322)

SCIM users deleted in bulk are not captured in the event log. We just
add an event like this:

![image](https://github.com/user-attachments/assets/2d7078b2-61d6-475e-8151-63b5b5ed7449)

This prevents partial user sync because we don't get an event when the
user was deleted.
This commit is contained in:
Gastón Fournier 2025-07-07 12:17:37 +02:00 committed by GitHub
parent f7e39df386
commit 5901475c9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 27 additions and 11 deletions

View File

@ -290,8 +290,12 @@ export class UserStore implements IUserStore {
await this.activeUsers().del(); await this.activeUsers().del();
} }
async deleteScimUsers(): Promise<void> { async deleteScimUsers(): Promise<User[]> {
await this.db(TABLE).whereNotNull('scim_id').del(); const rows = await this.db(TABLE)
.whereNotNull('scim_id')
.del()
.returning(USER_COLUMNS);
return rows.map(rowToUser);
} }
async count(): Promise<number> { async count(): Promise<number> {

View File

@ -403,14 +403,26 @@ class UserService {
} }
async deleteScimUsers(auditUser: IAuditUser): Promise<void> { async deleteScimUsers(auditUser: IAuditUser): Promise<void> {
await this.store.deleteScimUsers(); const users = await this.store.deleteScimUsers();
// Note: after deletion we can't get the role for the user
await this.eventService.storeEvent( const viewerRole = await this.accessService.getPredefinedRole(
RoleName.VIEWER,
);
if (users.length > 0) {
const deletions = users.map((user) => {
return new UserDeletedEvent({
deletedUser: { ...user, rootRole: viewerRole.id },
auditUser,
});
});
await this.eventService.storeEvents([
...deletions,
new ScimUsersDeleted({ new ScimUsersDeleted({
data: null, data: null,
auditUser, auditUser,
}), }),
); ]);
}
} }
async loginUser( async loginUser(

View File

@ -46,5 +46,5 @@ export interface IUserStore extends Store<IUser, number> {
count(): Promise<number>; count(): Promise<number>;
countRecentlyDeleted(): Promise<number>; countRecentlyDeleted(): Promise<number>;
countServiceAccounts(): Promise<number>; countServiceAccounts(): Promise<number>;
deleteScimUsers(): Promise<void>; deleteScimUsers(): Promise<IUser[]>;
} }

View File

@ -159,7 +159,7 @@ class UserStoreMock implements IUserStore {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
deleteScimUsers(): Promise<void> { deleteScimUsers(): Promise<User[]> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }