Files
thebet365/apps/api/src/applications/admin/admin-rbac.spec.ts
Mars ce84226219 feat(admin+api): 代理停用默认、结算加固与冒烟配置探针
- 代理层级默认授信比例与停用冻结/禁登全局默认

- 结算预览去重、比分校验、串关当场判负与市场类型校验

- 站内信 Banner/公告自动通知开关;开发环境动态 API 端口

- 扩充 RBAC/结算/认证/返现单元测试与 agent skills
2026-06-23 11:08:41 +08:00

123 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PermissionsGuard } from '../../domains/identity/guards';
import { isAuditListUnrestricted } from '../../domains/operations/audit/audit-list-scope';
import { PERMISSIONS_KEY } from '../../shared/common/decorators';
/** Mirrors run-seed.ts role permission assignments (SEC010SEC012). */
const ROLE_PERMISSIONS: Record<string, string[]> = {
SUPER_ADMIN: ['*'],
MATCH_ADMIN: [
'matches.manage',
'settlement.confirm',
'content.manage',
'bets.view',
'reports.view',
'audit.view',
],
FINANCE_ADMIN: [
'wallet.deposit',
'wallet.withdraw',
'cashback.confirm',
'agents.view',
'agents.credit',
'users.view',
'users.create',
'deposit.manage',
'deposit.review',
'reports.view',
'bets.view',
'audit.view',
],
SUPPORT: ['users.view', 'users.reset_password', 'bets.view', 'reports.view', 'audit.view'],
};
function mockContext(user: Record<string, unknown>): ExecutionContext {
return {
switchToHttp: () => ({
getRequest: () => ({ user }),
}),
getHandler: () => ({}),
getClass: () => ({}),
} as ExecutionContext;
}
function guardAllows(user: Record<string, unknown>, ...required: string[]): boolean {
const reflector = {
getAllAndOverride: (key: string) => (key === PERMISSIONS_KEY ? required : undefined),
} as unknown as Reflector;
const guard = new PermissionsGuard(reflector);
try {
return guard.canActivate(mockContext(user));
} catch {
return false;
}
}
function userWithRole(role: string) {
return {
userType: 'ADMIN',
role,
permissions: ROLE_PERMISSIONS[role] ?? [],
};
}
describe('Admin RBAC (SEC010SEC012)', () => {
it('SEC010: SUPPORT cannot perform wallet deposit', () => {
const user = userWithRole('SUPPORT');
expect(guardAllows(user, 'wallet.deposit')).toBe(false);
expect(guardAllows(user, 'users.view')).toBe(true);
expect(guardAllows(user, 'users.reset_password')).toBe(true);
});
it('SEC011: FINANCE_ADMIN cannot manage matches', () => {
const user = userWithRole('FINANCE_ADMIN');
expect(guardAllows(user, 'matches.manage')).toBe(false);
expect(guardAllows(user, 'wallet.deposit')).toBe(true);
expect(guardAllows(user, 'agents.credit')).toBe(true);
});
it('SEC012: MATCH_ADMIN cannot perform wallet deposit', () => {
const user = userWithRole('MATCH_ADMIN');
expect(guardAllows(user, 'wallet.deposit')).toBe(false);
expect(guardAllows(user, 'settlement.confirm')).toBe(true);
expect(guardAllows(user, 'content.manage')).toBe(true);
expect(guardAllows(user, 'settlement.resettle')).toBe(false);
});
it('FINANCE_ADMIN has deposit and cashback permissions but not reset database', () => {
const user = userWithRole('FINANCE_ADMIN');
expect(guardAllows(user, 'deposit.manage')).toBe(true);
expect(guardAllows(user, 'deposit.review')).toBe(true);
expect(guardAllows(user, 'cashback.confirm')).toBe(true);
expect(guardAllows(user, 'settings.reset_database')).toBe(false);
});
it('MATCH_ADMIN cannot manage deposits or confirm cashback', () => {
const user = userWithRole('MATCH_ADMIN');
expect(guardAllows(user, 'deposit.manage')).toBe(false);
expect(guardAllows(user, 'deposit.review')).toBe(false);
expect(guardAllows(user, 'cashback.confirm')).toBe(false);
});
it('SUPPORT cannot confirm cashback or manage deposits', () => {
const user = userWithRole('SUPPORT');
expect(guardAllows(user, 'cashback.confirm')).toBe(false);
expect(guardAllows(user, 'deposit.manage')).toBe(false);
expect(guardAllows(user, 'deposit.review')).toBe(false);
});
it('SUPER_ADMIN bypasses permission checks', () => {
const user = userWithRole('SUPER_ADMIN');
expect(guardAllows(user, 'wallet.deposit')).toBe(true);
expect(guardAllows(user, 'matches.manage')).toBe(true);
expect(guardAllows(user, 'settings.manage')).toBe(true);
});
it('audit list scope: only SUPER_ADMIN is unrestricted', () => {
expect(isAuditListUnrestricted('SUPER_ADMIN')).toBe(true);
expect(isAuditListUnrestricted('FINANCE_ADMIN')).toBe(false);
expect(isAuditListUnrestricted('MATCH_ADMIN')).toBe(false);
});
});