1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-23 13:46:45 +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();
}
async deleteScimUsers(): Promise<void> {
await this.db(TABLE).whereNotNull('scim_id').del();
async deleteScimUsers(): Promise<User[]> {
const rows = await this.db(TABLE)
.whereNotNull('scim_id')
.del()
.returning(USER_COLUMNS);
return rows.map(rowToUser);
}
async count(): Promise<number> {

View File

@ -403,14 +403,26 @@ class UserService {
}
async deleteScimUsers(auditUser: IAuditUser): Promise<void> {
await this.store.deleteScimUsers();
await this.eventService.storeEvent(
new ScimUsersDeleted({
data: null,
auditUser,
}),
const users = await this.store.deleteScimUsers();
// Note: after deletion we can't get the role for the user
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({
data: null,
auditUser,
}),
]);
}
}
async loginUser(

View File

@ -46,5 +46,5 @@ export interface IUserStore extends Store<IUser, number> {
count(): Promise<number>;
countRecentlyDeleted(): 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);
}
deleteScimUsers(): Promise<void> {
deleteScimUsers(): Promise<User[]> {
throw new Error('Method not implemented.');
}