fix: harden platform response projections
This commit is contained in:
@@ -29,11 +29,25 @@ for (const contract of expected) {
|
||||
if (resource.fields.length === 0 || resource.fields.some((field) => field.key === 'id' || field.key.endsWith('_id'))) failures.push(`${contract.name}: invalid allowlist`);
|
||||
const method = resource.mode === 'append_only' ? 'POST' : 'GET';
|
||||
if (!manifest.routes.some((route) => route.method === method && route.path === resource.resource)) failures.push(`${contract.name}: resource route mismatch`);
|
||||
if (resource.mode === 'readonly') { const view = files('src/views').find((file) => file.includes(resource.name) && file.endsWith('ListPage.vue')); if (!view || !fs.readFileSync(view, 'utf8').includes('ReadOnlyListPage')) failures.push(`${contract.name}: readonly UI`); }
|
||||
if (resource.mode === 'readonly') {
|
||||
const view = files('src/views').find((file) => file.includes(resource.name) && file.endsWith('ListPage.vue'));
|
||||
if (!view || !fs.readFileSync(view, 'utf8').includes('ReadOnlyListPage')) failures.push(`${contract.name}: readonly UI`);
|
||||
}
|
||||
}
|
||||
if (JSON.stringify(resources.map((item) => item.name).sort()) !== JSON.stringify(expected.map((item) => item.name).sort())) failures.push('catalogue names differ from backend ExpectedResources');
|
||||
for (const name of ['ec_category', 'platform_menu']) { const view = files('src/views').find((file) => file.includes(name) && file.endsWith('TreePage.vue')); if (!view) failures.push(`${name}: tree page missing`); }
|
||||
const tree = fs.readFileSync('src/views/shared/TreePage.vue', 'utf8');
|
||||
if (!tree.includes('parent_identity') || !tree.includes('canWrite') || !tree.includes('resourceApi.create') || !tree.includes('resourceApi.update')) failures.push('tree: writable identity actions missing');
|
||||
if (/(?:['"`]id['"`]|\bparent_id\b|\.id\b)/.test(tree)) failures.push('tree: internal id key leaked');
|
||||
const readOnlyPage = fs.readFileSync('src/views/shared/ReadOnlyListPage.vue', 'utf8');
|
||||
if (/resourceApi\.(?:create|update|archive)\b/.test(readOnlyPage)) failures.push('readonly: mutation action exposed');
|
||||
for (const detailPage of ['src/views/shared/CrudListPage.vue', 'src/views/shared/ReadOnlyListPage.vue']) {
|
||||
const source = fs.readFileSync(detailPage, 'utf8');
|
||||
if (!source.includes("key !== 'id'") || !source.includes("key.endsWith('_id')")) failures.push(`${detailPage}: internal ids shown in detail`);
|
||||
}
|
||||
const event = resources.find((resource) => resource.name === 'saf_event');
|
||||
const disposal = resources.find((resource) => resource.name === 'saf_event_disposal');
|
||||
if (!event?.detailActions?.some((action) => action.name === 'saf_event_disposal' && action.resource.includes(':identity/disposals'))) failures.push('saf_event_disposal: detail action missing');
|
||||
if (!disposal || disposal.resource !== '/safety/saf_event/:identity/disposals' || files('src/views').some((file) => file.includes('saf_event_disposal'))) failures.push('saf_event_disposal: independent page exposed');
|
||||
for (const failure of failures) console.log(failure);
|
||||
if (failures.length) process.exitCode = 1;
|
||||
|
||||
Reference in New Issue
Block a user