qwen_2.5_model / src /modules /auth /auth.controller.spec.ts
Muhammad Noman
Deploy OpenWA to Hugging Face Spaces
46252cd
Raw
History Blame Contribute Delete
4.01 kB
import type { Request } from 'express';
import { AuthController } from './auth.controller';
import { AuditAction } from '../audit/entities/audit-log.entity';
import type { ApiKey } from './entities/api-key.entity';
import type { AuthService } from './auth.service';
import type { AuditService } from '../audit/audit.service';
// API-key lifecycle operations (create / delete / revoke) must leave an audit trail — they were
// previously unrecorded. These assert the controller emits the matching audit action with the acting
// admin key, the resolved client IP, and the target key in metadata.
describe('AuthController — API-key lifecycle audit logging', () => {
const actor = { id: 'admin-key', name: 'admin' } as unknown as ApiKey;
const makeReq = (): Request =>
({ method: 'POST', path: '/auth/api-keys', clientIp: '203.0.113.7' }) as unknown as Request;
let authService: {
createApiKey: jest.Mock;
findOne: jest.Mock;
update: jest.Mock;
delete: jest.Mock;
revoke: jest.Mock;
};
let auditService: { logInfo: jest.Mock };
let controller: AuthController;
beforeEach(() => {
const createdKey = {
id: 'k1',
name: 'new-key',
role: 'user',
keyPrefix: 'ow_',
isActive: true,
usageCount: 0,
createdAt: new Date(),
};
authService = {
createApiKey: jest.fn().mockResolvedValue({ apiKey: createdKey, rawKey: 'raw-secret' }),
findOne: jest.fn().mockResolvedValue({
id: 'k1',
name: 'target-key',
role: 'viewer',
allowedIps: null,
allowedSessions: null,
expiresAt: null,
}),
update: jest.fn().mockResolvedValue({ ...createdKey, role: 'admin' }),
delete: jest.fn().mockResolvedValue(undefined),
revoke: jest.fn().mockResolvedValue({ ...createdKey, isActive: false }),
};
auditService = { logInfo: jest.fn().mockResolvedValue(null) };
controller = new AuthController(authService as unknown as AuthService, auditService as unknown as AuditService);
});
const lastContextFor = (
action: AuditAction,
):
| {
apiKey?: ApiKey;
ipAddress?: string;
metadata?: { targetKeyId?: string; before?: { role?: string }; after?: { role?: string } };
}
| undefined => {
const calls = auditService.logInfo.mock.calls as Array<
[
AuditAction,
{
apiKey?: ApiKey;
ipAddress?: string;
metadata?: { targetKeyId?: string; before?: { role?: string }; after?: { role?: string } };
},
]
>;
return calls.find(c => c[0] === action)?.[1];
};
it('logs API_KEY_CREATED on create, with the acting key, IP, and target id', async () => {
await controller.create({ name: 'new-key' }, makeReq(), actor);
const ctx = lastContextFor(AuditAction.API_KEY_CREATED);
expect(ctx).toBeDefined();
expect(ctx?.apiKey).toBe(actor);
expect(ctx?.ipAddress).toBe('203.0.113.7');
expect(ctx?.metadata?.targetKeyId).toBe('k1');
expect(JSON.stringify(auditService.logInfo.mock.calls)).not.toContain('raw-secret');
});
it('logs API_KEY_DELETED on delete', async () => {
await controller.delete('k1', makeReq(), actor);
expect(authService.delete).toHaveBeenCalledWith('k1');
expect(lastContextFor(AuditAction.API_KEY_DELETED)?.metadata?.targetKeyId).toBe('k1');
});
it('logs API_KEY_UPDATED with before/after authorization state', async () => {
await controller.update('k1', { role: 'admin' } as never, makeReq(), actor);
const ctx = lastContextFor(AuditAction.API_KEY_UPDATED);
expect(ctx?.apiKey).toBe(actor);
expect(ctx?.metadata?.targetKeyId).toBe('k1');
expect(ctx?.metadata?.before?.role).toBe('viewer');
expect(ctx?.metadata?.after?.role).toBe('admin');
});
it('logs API_KEY_REVOKED on revoke', async () => {
await controller.revoke('k1', makeReq(), actor);
expect(lastContextFor(AuditAction.API_KEY_REVOKED)?.metadata?.targetKeyId).toBe('k1');
});
});