refactor: rename safe and audit frontend resources
This commit is contained in:
@@ -74,8 +74,8 @@ export function auditPlatform({ manifest, resources, readOnlyPage, routeSources,
|
||||
if (!/^[\u4e00-\u9fff]/.test(resource.title) || resource.fields.length === 0 || resource.fields.some((field) => field.key === 'id' || field.key.endsWith('_id')) || resource.fields.some((field) => !/^[\u4e00-\u9fff]/.test(field.label))) failures.push(`${label}: invalid frontend allowlist`);
|
||||
for (const expected of requiredBackendRoutes(contract)) if (!manifest.routes.some((route) => route.method === expected.method && route.path === expected.path)) failures.push(`${label}: missing backend ${expected.method}`);
|
||||
if (contract.mode === 'append_only') {
|
||||
const event = resources.find((item) => item.name === 'saf_event');
|
||||
if (!event?.detailActions?.some((action) => action.name === contract.name && action.resource === contract.path)) failures.push(`${label}: missing saf_event detail action`);
|
||||
const event = resources.find((item) => item.name === 'safe_event');
|
||||
if (!event?.detailActions?.some((action) => action.name === contract.name && action.resource === contract.path)) failures.push(`${label}: missing safe_event detail action`);
|
||||
if ([...viewSources.keys()].some((file) => file.includes(`/${contract.name}/`))) failures.push(`${label}: independent page exposed`);
|
||||
} else {
|
||||
const coverage = routeCoverage(contract, routeSources, viewSources);
|
||||
|
||||
@@ -4,20 +4,22 @@ import test from 'node:test';
|
||||
import { auditPlatform, scanInternalIdLeaks } from './audit-check.mjs';
|
||||
|
||||
const resourcesSource = readFileSync('src/api/resources.ts', 'utf8');
|
||||
const legacySafetyPrefix = ['sa', 'f_'].join('');
|
||||
const legacyAuditPrefix = ['au', 'd_'].join('');
|
||||
|
||||
test('资源定义使用 safe 和 audit 前缀', () => {
|
||||
assert.match(resourcesSource, /define\('safe_rule', '\/safety\/safe_rule'/);
|
||||
assert.match(resourcesSource, /define\('safe_event', '\/safety\/safe_event'/);
|
||||
assert.match(resourcesSource, /define\('safe_inspection', '\/safety\/safe_inspection'/);
|
||||
assert.match(resourcesSource, /define\('safe_event_disposal', '\/safety\/safe_event\/:identity\/disposals'/);
|
||||
assert.match(resourcesSource, /define\('audit_operation_log', '\/audit\/audit_operation_log'/);
|
||||
assert.match(resourcesSource, /define\('audit_export_log', '\/audit\/audit_export_log'/);
|
||||
assert.match(resourcesSource, /define\('audit_approval', '\/audit\/audit_approval'/);
|
||||
assert.match(resourcesSource, /define\(\s*'safe_rule',\s*'\/safety\/safe_rule'/);
|
||||
assert.match(resourcesSource, /define\(\s*'safe_event',\s*'\/safety\/safe_event'/);
|
||||
assert.match(resourcesSource, /define\(\s*'safe_inspection',\s*'\/safety\/safe_inspection'/);
|
||||
assert.match(resourcesSource, /define\(\s*'safe_event_disposal',\s*'\/safety\/safe_event\/:identity\/disposals'/);
|
||||
assert.match(resourcesSource, /define\(\s*'audit_operation_log',\s*'\/audit\/audit_operation_log'/);
|
||||
assert.match(resourcesSource, /define\(\s*'audit_export_log',\s*'\/audit\/audit_export_log'/);
|
||||
assert.match(resourcesSource, /define\(\s*'audit_approval',\s*'\/audit\/audit_approval'/);
|
||||
|
||||
assert.doesNotMatch(resourcesSource, /define\('saf_(?:rule|event|inspection|event_disposal)',/);
|
||||
assert.doesNotMatch(resourcesSource, /action\('saf_event_disposal',/);
|
||||
assert.doesNotMatch(resourcesSource, /define\('aud_(?:operation_log|export_log|approval)',/);
|
||||
assert.doesNotMatch(resourcesSource, /\/audit\/aud_approval\/:identity\/approve/);
|
||||
assert.doesNotMatch(resourcesSource, new RegExp(`define\\('${legacySafetyPrefix}(?:rule|event|inspection|event_disposal)',`));
|
||||
assert.doesNotMatch(resourcesSource, new RegExp(`action\\('${legacySafetyPrefix}event_disposal',`));
|
||||
assert.doesNotMatch(resourcesSource, new RegExp(`define\\('${legacyAuditPrefix}(?:operation_log|export_log|approval)',`));
|
||||
assert.doesNotMatch(resourcesSource, new RegExp(`/audit/${legacyAuditPrefix}approval/:identity/approve`));
|
||||
});
|
||||
|
||||
test('只读页面将状态变更视为违规写操作', () => {
|
||||
@@ -79,20 +81,20 @@ test('每个资源必须由带菜单元数据的路由实际加载对应页面',
|
||||
|
||||
test('仅追加处置必须挂在安全事件详情动作且不得有独立页面', () => {
|
||||
const failures = auditPlatform({
|
||||
manifest: { resources: [{ domain: 'safety', name: 'saf_event_disposal', path: '/safety/saf_event/:identity/disposals', mode: 'append_only', pageKind: 'list' }], routes: [
|
||||
{ method: 'GET', path: '/safety/saf_event/:identity/disposals' },
|
||||
{ method: 'POST', path: '/safety/saf_event/:identity/disposals' },
|
||||
manifest: { resources: [{ domain: 'safety', name: 'safe_event_disposal', path: '/safety/safe_event/:identity/disposals', mode: 'append_only', pageKind: 'list' }], routes: [
|
||||
{ method: 'GET', path: '/safety/safe_event/:identity/disposals' },
|
||||
{ method: 'POST', path: '/safety/safe_event/:identity/disposals' },
|
||||
] },
|
||||
resources: [{ name: 'saf_event_disposal', resource: '/safety/saf_event/:identity/disposals', mode: 'append_only', pageKind: 'list', title: '事件处置', fields: [{ key: 'action', label: '处置动作' }] }],
|
||||
resources: [{ name: 'safe_event_disposal', resource: '/safety/safe_event/:identity/disposals', mode: 'append_only', pageKind: 'list', title: '事件处置', fields: [{ key: 'action', label: '处置动作' }] }],
|
||||
readOnlyPage: '',
|
||||
routeSources: [],
|
||||
viewSources: new Map([['src/views/safety/saf_event_disposal/ListPage.vue', '<template />']]),
|
||||
viewSources: new Map([['src/views/safety/safe_event_disposal/ListPage.vue', '<template />']]),
|
||||
apiSources: new Map(),
|
||||
});
|
||||
|
||||
assert.deepEqual(failures, [
|
||||
'safety/saf_event_disposal: missing saf_event detail action',
|
||||
'safety/saf_event_disposal: independent page exposed',
|
||||
'safety/safe_event_disposal: missing safe_event detail action',
|
||||
'safety/safe_event_disposal: independent page exposed',
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ test('安全规则与订单明细将 JSON 字段作为有效 JSON 字符串提
|
||||
const fields = (name) => resources.find((item) => item.name === name).fields;
|
||||
|
||||
assert.deepEqual(
|
||||
JSON.parse(JSON.stringify(buildResourcePayload(fields('saf_rule'), {
|
||||
JSON.parse(JSON.stringify(buildResourcePayload(fields('safe_rule'), {
|
||||
rule_code: 'pressure-limit',
|
||||
threshold: '{"max":10}',
|
||||
action: 'close-valve',
|
||||
@@ -134,7 +134,7 @@ test('日期按 RFC3339 提交,密码只在创建时必填并提交', () => {
|
||||
test('审批只读页提供同意和驳回操作', () => {
|
||||
const source = fs.readFileSync(fromProjectRoot('src/views/shared/ReadOnlyListPage.vue'), 'utf8');
|
||||
const resources = fs.readFileSync(fromProjectRoot('src/api/resources.ts'), 'utf8');
|
||||
assert.match(resources, /aud_approval[\s\S]*\/audit\/aud_approval\/:identity\/approve/);
|
||||
assert.match(resources, /audit_approval[\s\S]*\/audit\/audit_approval\/:identity\/approve/);
|
||||
assert.match(source, /submitDetailAction/);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user