Files
Agent-System/web/src/engine/rbac.test.ts
T
weichenandCursor a56d033d3c feat(web): fail-closed capabilities and admin roles from server API
Stop persisting roles to localStorage as authority; AdminSettingsModal reads
and writes role matrices via /api/v1/admin/roles; hasPermission denies when
capabilities are not loaded from /auth/me.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 02:50:22 +00:00

260 lines
10 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
DEFAULT_ROLES,
hasPermission,
isDeliverableVisible,
filterVisibleDeliverablesWithRBAC,
canPerformDocAction,
capabilitiesFromRole,
} from './rbac';
import { UserProfile } from '../types/docgov';
import { DeliverableItem } from '../types/workbench';
const sampleUsers: Record<string, UserProfile> = {
admin: {
id: 100,
name: '系统管理员',
employeeId: 'ADMIN-001',
department: '系统运维部',
position: '系统管理员',
roleId: 'role-admin',
},
director: {
id: 4,
name: '王总监',
employeeId: 'SMDF-0018',
department: '医疗器械研发事业部',
position: '微创器械研发总监',
roleId: 'role-director',
},
lead: {
id: 3,
name: '李主管',
employeeId: 'SMDF-0205',
department: '机器人与微创内窥镜研发中心',
position: '研发项目技术主管',
roleId: 'role-tech-lead',
},
engineer: {
id: 2,
name: '张工',
employeeId: 'SMDF-0821',
department: '机器人与微创内窥镜研发中心',
position: '资深医疗器械方案工程师',
roleId: 'role-engineer',
},
guest: {
id: 99,
name: '外部审计专员',
employeeId: 'GUEST-001',
department: '第三方认证机构',
position: '外部合规审查员',
roleId: 'role-guest',
},
};
const createMockDoc = (overrides: Partial<DeliverableItem> = {}): DeliverableItem => ({
docId: 'doc-mock-001',
projectId: 1,
taskKey: 'feasibility',
title: '测试受控交付物',
stage: 'V0.1',
category: 'workflow',
creatorId: 2,
creatorName: '张工',
isFixedWorkflow: true,
isTemplateOnly: false,
lifecycleState: 'drafting',
isClaimed: true,
author: '张工',
reviewer: '李主管',
approver: '王总监',
updatedAt: '2026-09-08 12:00',
...overrides,
});
test('用例 1: DEFAULT_ROLES 包含 5 种默认角色且具备预期权限', () => {
assert.equal(DEFAULT_ROLES.length, 5);
const admin = DEFAULT_ROLES.find((r) => r.code === 'ADMIN');
const engineer = DEFAULT_ROLES.find((r) => r.code === 'ENGINEER');
const guest = DEFAULT_ROLES.find((r) => r.code === 'GUEST');
assert.ok(admin);
assert.ok(admin.isSystem);
assert.ok(admin.permissions.includes('perm:manage'));
assert.ok(engineer);
assert.ok(engineer.permissions.includes('workflow:view_all'));
assert.equal(engineer.permissions.includes('project:create'), false);
assert.ok(guest);
assert.equal(guest.permissions.includes('workflow:view_all'), false);
});
test('用例 2: 系统管理员 (ADMIN) 与具备 perm:manage 用户的通配豁免特权', () => {
const adminCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-admin');
const engineerCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-engineer');
assert.equal(hasPermission(sampleUsers.admin, DEFAULT_ROLES, 'project:create', adminCaps), true);
assert.equal(hasPermission(sampleUsers.admin, DEFAULT_ROLES, 'perm:manage', adminCaps), true);
assert.equal(hasPermission(sampleUsers.admin, DEFAULT_ROLES, 'doc:override_visibility', adminCaps), true);
// 普通工程师无管理权限
assert.equal(hasPermission(sampleUsers.engineer, DEFAULT_ROLES, 'perm:manage', engineerCaps), false);
assert.equal(hasPermission(sampleUsers.engineer, DEFAULT_ROLES, 'project:create', engineerCaps), false);
// fail closed:未加载 capabilities 时拒绝
assert.equal(hasPermission(sampleUsers.admin, DEFAULT_ROLES, 'project:create'), false);
});
test('用例 3: 常规工作流基线可见性 (workflow:view_all) 判定', () => {
const normalDoc = createMockDoc();
// 工程师有 workflow:view_all -> 可见
assert.equal(isDeliverableVisible(sampleUsers.engineer, DEFAULT_ROLES, normalDoc), true);
// 外部审计员无 workflow:view_all 且不是责任人 -> 不可见
assert.equal(isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, normalDoc), false);
});
test('用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见,其他用户被精确拦截)', () => {
const restrictedDoc = createMockDoc({
author: '张工',
reviewer: '李主管',
approver: '赵院长', // 王总监不是责任人
visibilityRule: {
mode: 'designated_only',
overrideReason: '敏感临床事故报告,收紧仅责任人可见',
configuredBy: '李主管',
configuredAt: '2026-09-08 14:00',
},
});
// 张工是编制人 -> 可见
assert.equal(isDeliverableVisible(sampleUsers.engineer, DEFAULT_ROLES, restrictedDoc), true);
// 李主管是审核人 -> 可见
assert.equal(isDeliverableVisible(sampleUsers.lead, DEFAULT_ROLES, restrictedDoc), true);
// 王总监虽为研发总监,但非三权责任人 -> 被单文档覆盖拦截 (不可见)
assert.equal(isDeliverableVisible(sampleUsers.director, DEFAULT_ROLES, restrictedDoc), false);
// 系统管理员超级权限仍可见
assert.equal(isDeliverableVisible(sampleUsers.admin, DEFAULT_ROLES, restrictedDoc), true);
});
test('用例 5: 单文档覆盖 - role_whitelist (仅白名单内角色可见,其他角色被精确拦截)', () => {
const secretPatentDoc = createMockDoc({
author: '外聘专家',
reviewer: '外聘审查',
approver: '外聘顾问',
visibilityRule: {
mode: 'role_whitelist',
allowedRoleIds: ['role-director'], // 仅总监可见
overrideReason: '核心专利保密算法拆解',
},
});
// 王总监拥有 role-director -> 可见
assert.equal(isDeliverableVisible(sampleUsers.director, DEFAULT_ROLES, secretPatentDoc), true);
// 张工 (role-engineer) 不在白名单中 -> 不可见
assert.equal(isDeliverableVisible(sampleUsers.engineer, DEFAULT_ROLES, secretPatentDoc), false);
// 李主管 (role-tech-lead) 不在白名单中 -> 不可见
assert.equal(isDeliverableVisible(sampleUsers.lead, DEFAULT_ROLES, secretPatentDoc), false);
});
test('用例 6: 单文档覆盖 - public (放宽可见性,无 workflow:view_all 权限的访客也能查阅)', () => {
const publicSpecDoc = createMockDoc({
author: '张工',
reviewer: '李主管',
approver: '王总监',
visibilityRule: {
mode: 'public',
overrideReason: '产品公开白皮书,供外部审计或用户公开查阅',
},
});
// 访客原本无 workflow:view_all,但单文档设为 public -> 可见
assert.equal(isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, publicSpecDoc), true);
});
test('用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖,非创建者绝对不可见)', () => {
const privateDraft = createMockDoc({
category: 'private',
creatorId: 2, // 张工创建
creatorName: '张工',
visibilityRule: {
mode: 'public', // 即使误设 public 也绝不能穿透 private 隔离
},
});
// 创建者本人可见
assert.equal(isDeliverableVisible(sampleUsers.engineer, DEFAULT_ROLES, privateDraft), true);
// 其他人不可见
assert.equal(isDeliverableVisible(sampleUsers.lead, DEFAULT_ROLES, privateDraft), false);
assert.equal(isDeliverableVisible(sampleUsers.director, DEFAULT_ROLES, privateDraft), false);
assert.equal(isDeliverableVisible(sampleUsers.admin, DEFAULT_ROLES, privateDraft), false);
assert.equal(isDeliverableVisible(sampleUsers.guest, DEFAULT_ROLES, privateDraft), false);
});
test('用例 8: 核心业务动作权限拦截判定 (canPerformDocAction & hasPermission)', () => {
const directorCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-director');
const leadCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-tech-lead');
const engineerCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-engineer');
const guestCaps = capabilitiesFromRole(DEFAULT_ROLES, 'role-guest');
// 1. 创建项目权限
assert.equal(canPerformDocAction('create_project', sampleUsers.director, DEFAULT_ROLES, directorCaps), true);
assert.equal(canPerformDocAction('create_project', sampleUsers.lead, DEFAULT_ROLES, leadCaps), true);
assert.equal(canPerformDocAction('create_project', sampleUsers.engineer, DEFAULT_ROLES, engineerCaps), false);
assert.equal(canPerformDocAction('create_project', sampleUsers.guest, DEFAULT_ROLES, guestCaps), false);
// 2. 指派文档法定三权责任人
assert.equal(canPerformDocAction('assign_lead', sampleUsers.director, DEFAULT_ROLES, directorCaps), true);
assert.equal(canPerformDocAction('assign_lead', sampleUsers.lead, DEFAULT_ROLES, leadCaps), true);
assert.equal(canPerformDocAction('assign_lead', sampleUsers.engineer, DEFAULT_ROLES, engineerCaps), false);
// 3. 配置单文档覆盖
assert.equal(canPerformDocAction('override_visibility', sampleUsers.director, DEFAULT_ROLES, directorCaps), true);
assert.equal(canPerformDocAction('override_visibility', sampleUsers.lead, DEFAULT_ROLES, leadCaps), true);
assert.equal(canPerformDocAction('override_visibility', sampleUsers.engineer, DEFAULT_ROLES, engineerCaps), false);
// 4. 服务端下发升级后的 capabilities 立即生效
const upgradedEngineerCaps = [...engineerCaps, 'project:create' as const];
assert.equal(canPerformDocAction('create_project', sampleUsers.engineer, DEFAULT_ROLES, upgradedEngineerCaps), true);
});
test('用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交付物', () => {
const docs: DeliverableItem[] = [
createMockDoc({ docId: 'doc-1', title: '常规工作流' }),
createMockDoc({
docId: 'doc-2',
title: '绝密算法',
author: '外聘专家',
visibilityRule: { mode: 'role_whitelist', allowedRoleIds: ['role-director'] },
}),
createMockDoc({
docId: 'doc-3',
title: '张工个人草案',
category: 'private',
creatorId: 2,
}),
];
// 张工视角: 能看常规工作流(doc-1)和个人草案(doc-3),不能看绝密算法(doc-2)
const zhangVisible = filterVisibleDeliverablesWithRBAC(docs, sampleUsers.engineer, DEFAULT_ROLES);
assert.deepEqual(
zhangVisible.map((d) => d.docId),
['doc-1', 'doc-3']
);
// 王总监视角: 能看常规工作流(doc-1)和绝密算法(doc-2),不能看张工私密草案(doc-3)
const wangVisible = filterVisibleDeliverablesWithRBAC(docs, sampleUsers.director, DEFAULT_ROLES);
assert.deepEqual(
wangVisible.map((d) => d.docId),
['doc-1', 'doc-2']
);
});