feat: harden sessions and track downstream acknowledgements

This commit is contained in:
hectorzhao
2026-07-14 14:18:43 +08:00
parent 3d37adcc9f
commit 8c03663f24
43 changed files with 1733 additions and 150 deletions
+25
View File
@@ -84,4 +84,29 @@ describe('UsersService', () => {
data: expect.objectContaining({ action: 'user.created', resource: 'user' }),
}));
});
it('revokes the affected user session when a role is assigned', async () => {
const tx = {
userRole: { upsert: jest.fn().mockResolvedValue({ userId: 'user-1', roleId: 'role-1' }) },
user: { update: jest.fn().mockResolvedValue({ id: 'user-1' }) },
};
const prisma = { $transaction: jest.fn((callback) => callback(tx)) };
const service = new UsersService(prisma as never);
await service.assignRole({ userId: 'user-1', roleId: 'role-1' });
expect(tx.user.update).toHaveBeenCalledWith({ where: { id: 'user-1' }, data: { sessionVersion: { increment: 1 } } });
});
it('revokes every affected user session when role permissions change', async () => {
const tx = {
rolePermission: { upsert: jest.fn().mockResolvedValue({ roleId: 'role-1', permissionId: 'permission-1' }) },
user: { updateMany: jest.fn().mockResolvedValue({ count: 2 }) },
};
const prisma = { $transaction: jest.fn((callback) => callback(tx)) };
const service = new UsersService(prisma as never);
await service.assignPermission({ roleId: 'role-1', permissionId: 'permission-1' });
expect(tx.user.updateMany).toHaveBeenCalledWith({
where: { roles: { some: { roleId: 'role-1' } } },
data: { sessionVersion: { increment: 1 } },
});
});
});