import 'reflect-metadata'; import { GUARDS_METADATA } from '@nestjs/common/constants'; import { Role } from '@prisma/client'; import { describe, expect, it } from 'vitest'; import { ROLES_KEY } from '../auth/decorators/roles.decorator'; import { DkvController } from '../dkv/dkv.controller'; import { ModuleGrantsController } from '../groups/module-grants.controller'; import { HandelswareDatevController } from '../handelsware-datev/handelsware-datev.controller'; import { KantineDatevController } from '../kantine-datev/kantine-datev.controller'; import { ProxmoxController } from '../proxmox/proxmox.controller'; import { TendersController } from '../tenders/tenders.controller'; import { ModuleRegistryController } from './module-registry.controller'; import { MODULE_MANAGE_KEY, MODULE_SLUG_KEY, ModuleGuard } from './module.guard'; /** * Metadaten-Beweis für die Freigabestufe Verwalten (261002-icv, L-04/L-09): * welche Handler auf `@ModuleManage` umgestellt wurden und welche bewusst * Administratoren vorbehalten bleiben (T-icv-01/06/07/08). Reine Metadaten — * kein Nest-Start, keine Datenbank. */ const ADMIN_ONLY = [Role.ADMIN, Role.SUPER_ADMIN]; function methodsOf(controller: { prototype: object }): string[] { return Object.getOwnPropertyNames(controller.prototype).filter( (name) => name !== 'constructor' && typeof (controller.prototype as any)[name] === 'function', ); } function handler(controller: { prototype: object }, name: string) { return (controller.prototype as any)[name]; } function expectManage(controller: { prototype: object }, name: string, slug: string) { const fn = handler(controller, name); expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn), `${name} MODULE_MANAGE_KEY`).toBe(true); expect(Reflect.getMetadata(MODULE_SLUG_KEY, fn), `${name} MODULE_SLUG_KEY`).toBe(slug); expect(Reflect.getMetadata(GUARDS_METADATA, fn), `${name} guards`).toContain(ModuleGuard); expect(Reflect.getMetadata(ROLES_KEY, fn), `${name} ROLES_KEY`).toBeUndefined(); } function expectAdminOnly(controller: { prototype: object }, name: string) { const fn = handler(controller, name); expect(Reflect.getMetadata(ROLES_KEY, fn), `${name} ROLES_KEY`).toEqual(ADMIN_ONLY); expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn), `${name} MODULE_MANAGE_KEY`).toBeUndefined(); } describe('Umgestellte Handler (Verwalten)', () => { it('DkvController: ganze Klasse Verwalten, kein Handler trägt @Roles', () => { expect(Reflect.getMetadata(MODULE_SLUG_KEY, DkvController)).toBe('dkv-fleet'); expect(Reflect.getMetadata(MODULE_MANAGE_KEY, DkvController)).toBe(true); expect(Reflect.getMetadata(GUARDS_METADATA, DkvController)).toContain(ModuleGuard); const names = methodsOf(DkvController).filter((n) => Reflect.hasMetadata('path', handler(DkvController, n))); expect(names.length).toBe(11); for (const name of names) { expect(Reflect.getMetadata(ROLES_KEY, handler(DkvController, name)), name).toBeUndefined(); } }); it.each(['create', 'update', 'remove', 'poll', 'test', 'testDraft'])( 'ProxmoxController.%s verlangt Verwalten für proxmox', (name) => { expectManage(ProxmoxController, name, 'proxmox'); }, ); it('ProxmoxController.list bleibt auf Benutzen-Ebene', () => { const fn = handler(ProxmoxController, 'list'); expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined(); expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined(); }); it('KantineDatevController.saveSettings und HandelswareDatevController.saveSettings verlangen Verwalten', () => { expectManage(KantineDatevController, 'saveSettings', 'kantine-datev'); expectManage(HandelswareDatevController, 'saveSettings', 'handelsware-datev'); }); }); describe('Bewusst nur für Administratoren (T-icv-01, T-icv-07)', () => { it.each(['getSourceConfig', 'saveSourceConfig', 'pollNow'])( 'TendersController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => { expectAdminOnly(TendersController, name); }, ); it.each(['matrix', 'userAccess', 'create', 'remove'])( 'ModuleGrantsController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => { expectAdminOnly(ModuleGrantsController, name); }, ); it.each(['activate', 'deactivate'])( 'ModuleRegistryController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => { expectAdminOnly(ModuleRegistryController, name); }, ); });