Files
RiskAgent/src/rbac/__tests__/configChange.property45.test.ts
T
freedakgmail c670b9e454 外包风险评估系统:领域引擎+前端+服务端持久化与生产部署
- 确定性领域引擎(分类/评分/分级/红线/费用/裁决)+LLM(通义千问)语言理解
- 6步评估向导、服务端草稿持久化(跨设备/编辑草稿保护)
- 工作流(草稿→风控→管理层)、RBAC、报告导出、校准、客户/费率/红线/最低工资管理
- 专业图标体系替换全部emoji、看板美化
- 生产化:API_BASE可配置(同源反代)、auth密钥惰性读取修复RBAC
- 444单测+204前端测试+51 e2e
2026-06-13 01:06:39 +08:00

99 lines
3.6 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.
/**
* Property 45: 非管理员配置修改一律拒绝且配置不变 的属性化测试(RBAC,Req 12.1, 12.3)。
*
* 属性陈述:对任意非 Administrator 角色(含 Assessor、未认证、未授权)发起的
* Risk_Model 配置修改请求,System 必拒绝该请求(status='rejected')、保持当前配置
* 不变(返回与请求中 currentConfig 同一引用且值相等),并返回权限不足错误
* AuthorizationErroruserMessage 含「权限不足」)。
*
* 测试中 `apply` 故意产出一个不同于当前配置的新值;若拒绝逻辑被绕过而调用了
* `apply`,返回的配置将发生变化,断言即会失败——以此真实校验"配置不变"。
*
* Feature: outsourcing-risk-assessment, Property 45: 非管理员配置修改一律拒绝且配置不变
* Validates: Requirements 12.1, 12.3
*/
import { describe, expect, it } from 'vitest';
import fc from 'fast-check';
import {
applyConfigChange,
AuthorizationError,
InMemoryConfigAuditStore,
type Actor,
type AuthRole,
} from '../index.js';
// 非 Administrator 角色全集(Req 12.1, 12.3)。
const NON_ADMIN_ROLES = ['Assessor', '未认证', '未授权'] as const satisfies readonly AuthRole[];
const nonAdminActorArb: fc.Arbitrary<Actor> = fc.record({
id: fc.string({ minLength: 0, maxLength: 12 }),
role: fc.constantFrom<AuthRole>(...NON_ADMIN_ROLES),
});
/** 任意配置值(以简单可比较对象代表 Risk_Model 配置形态)。 */
interface TestConfig {
readonly version: number;
readonly name: string;
}
const configArb: fc.Arbitrary<TestConfig> = fc.record({
version: fc.integer({ min: 0, max: 1_000 }),
name: fc.string({ minLength: 0, maxLength: 10 }),
});
const changedKeysArb: fc.Arbitrary<string[]> = fc.array(
fc.string({ minLength: 1, maxLength: 8 }),
{ minLength: 0, maxLength: 4 },
);
describe('Property 45: 非管理员配置修改一律拒绝且配置不变 (Req 12.1, 12.3)', () => {
it('非 Administrator 请求被拒绝、配置不变并返回权限不足错误', () => {
fc.assert(
fc.property(
nonAdminActorArb,
configArb,
changedKeysArb,
(actor, currentConfig, changedConfigKeys) => {
const auditStore = new InMemoryConfigAuditStore();
let applyCalled = false;
const result = applyConfigChange<TestConfig>(
{
actor,
currentConfig,
changedConfigKeys,
// 故意产出与当前配置不同的值:若被调用,配置必然改变。
apply: (current) => {
applyCalled = true;
return { version: current.version + 1, name: `${current.name}!` };
},
},
auditStore,
);
// 1) 一律拒绝(Req 12.1, 12.3)。
expect(result.status).toBe('rejected');
// 2) 鉴权失败时绝不调用 apply(保证配置不会被改动)。
expect(applyCalled).toBe(false);
// 3) 配置不变:同一引用且值相等(Req 12.1, 12.3)。
expect(result.config).toBe(currentConfig);
expect(result.config).toEqual(currentConfig);
// 4) 返回权限不足错误(Req 12.1, 12.3)。
if (result.status === 'rejected') {
expect(result.error).toBeInstanceOf(AuthorizationError);
expect(result.error.userMessage).toContain('权限不足');
expect(result.error.requiredRole).toBe('Administrator');
expect(result.error.actualRole).toBe(actor.role);
expect(result.error.actorId).toBe(actor.id);
}
},
),
{ numRuns: 100 },
);
});
});