feat(audit): 增加审计事件基础模块
This commit is contained in:
74
apps/server/src/modules/audit/audit.service.spec.ts
Normal file
74
apps/server/src/modules/audit/audit.service.spec.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { AuditService } from './audit.service';
|
||||
|
||||
describe('AuditService', () => {
|
||||
const create = jest.fn();
|
||||
const findMany = jest.fn();
|
||||
const prisma = { auditEvent: { create, findMany } } as any;
|
||||
const service = new AuditService(prisma);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('writes append-only audit events with sensitive fields redacted', async () => {
|
||||
create.mockResolvedValue({ id: 'audit-1' });
|
||||
|
||||
await service.record({
|
||||
actor: { id: 'm-8', name: '超级管理员', roleId: 'role-admin' },
|
||||
action: 'product.update',
|
||||
entityType: 'product',
|
||||
entityId: 'product-1',
|
||||
productId: 'product-1',
|
||||
before: { name: 'Old', password: '123456' },
|
||||
after: { name: 'New', nested: { apiKey: 'sk-test', keep: 'visible' } },
|
||||
metadata: { authorization: 'Bearer token', reason: 'manual edit' },
|
||||
});
|
||||
|
||||
expect(create).toHaveBeenCalledWith({
|
||||
data: expect.objectContaining({
|
||||
actorId: 'm-8',
|
||||
actorName: '超级管理员',
|
||||
action: 'product.update',
|
||||
entityType: 'product',
|
||||
entityId: 'product-1',
|
||||
productId: 'product-1',
|
||||
before: { name: 'Old', password: '[REDACTED]' },
|
||||
after: { name: 'New', nested: { apiKey: '[REDACTED]', keep: 'visible' } },
|
||||
metadata: { authorization: '[REDACTED]', reason: 'manual edit' },
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it('queries by actor, entity, scope, and date range with bounded page size', async () => {
|
||||
findMany.mockResolvedValue([]);
|
||||
|
||||
await service.query({
|
||||
actorId: 'm-8',
|
||||
entityType: 'bug',
|
||||
entityId: 'bug-1',
|
||||
productId: 'product-1',
|
||||
projectId: 'project-1',
|
||||
versionId: 'version-1',
|
||||
dateFrom: '2026-07-01T00:00:00.000Z',
|
||||
dateTo: '2026-07-08T23:59:59.000Z',
|
||||
take: '500',
|
||||
});
|
||||
|
||||
expect(findMany).toHaveBeenCalledWith({
|
||||
where: {
|
||||
actorId: 'm-8',
|
||||
entityType: 'bug',
|
||||
entityId: 'bug-1',
|
||||
productId: 'product-1',
|
||||
projectId: 'project-1',
|
||||
versionId: 'version-1',
|
||||
createdAt: {
|
||||
gte: new Date('2026-07-01T00:00:00.000Z'),
|
||||
lte: new Date('2026-07-08T23:59:59.000Z'),
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 100,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user