import fs from 'node:fs'; import path from 'node:path'; import vm from 'node:vm'; import ts from 'typescript'; const contracts = [ { "domain": "gas", "name": "gas_basic", "resource": "/gas/gas_basic", "mode": "writable", "pageKind": "list", "fields": [ { "key": "code", "required": true }, { "key": "name", "required": true }, { "key": "credit_code", "required": false }, { "key": "principal", "required": false }, { "key": "address", "required": false }, { "key": "longitude", "required": false }, { "key": "latitude", "required": false } ] }, { "domain": "gas", "name": "gas_account", "resource": "/gas/gas_account", "mode": "writable", "pageKind": "list", "fields": [ { "key": "username", "required": true }, { "key": "password", "required": true }, { "key": "display_name", "required": false }, { "key": "role_code", "required": false }, { "key": "gas_basic_identity", "required": true } ] }, { "domain": "delivery", "name": "delivery_basic", "resource": "/delivery/delivery_basic", "mode": "writable", "pageKind": "list", "fields": [ { "key": "delivery_code", "required": true }, { "key": "name", "required": true }, { "key": "gas_basic_identity", "required": false }, { "key": "principal", "required": false }, { "key": "address", "required": false } ] }, { "domain": "delivery", "name": "delivery_account", "resource": "/delivery/delivery_account", "mode": "writable", "pageKind": "list", "fields": [ { "key": "username", "required": true }, { "key": "password", "required": true }, { "key": "display_name", "required": false }, { "key": "role_code", "required": false }, { "key": "delivery_basic_identity", "required": true } ] }, { "domain": "delivery", "name": "delivery_task", "resource": "/delivery/delivery_task", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_order_identity", "required": true }, { "key": "delivery_basic_identity", "required": true }, { "key": "staff_account_identity", "required": false } ] }, { "domain": "delivery", "name": "delivery_track", "resource": "/delivery/delivery_track", "mode": "writable", "pageKind": "list", "fields": [ { "key": "delivery_task_identity", "required": true }, { "key": "started_at", "required": false }, { "key": "completed_at", "required": false } ] }, { "domain": "delivery", "name": "delivery_track_point", "resource": "/delivery/delivery_track_point", "mode": "writable", "pageKind": "list", "fields": [ { "key": "delivery_track_identity", "required": true }, { "key": "point_type", "required": true }, { "key": "occurred_at", "required": true }, { "key": "longitude", "required": true }, { "key": "latitude", "required": true } ] }, { "domain": "staff", "name": "staff_account", "resource": "/staff/account", "mode": "writable", "pageKind": "list", "fields": [ { "key": "username", "required": true }, { "key": "password", "required": true }, { "key": "name", "required": true }, { "key": "phone", "required": false }, { "key": "avatar", "required": false }, { "key": "role_code", "required": false }, { "key": "gas_basic_identity", "required": false }, { "key": "delivery_basic_identity", "required": false }, { "key": "work_status", "required": false } ] }, { "domain": "staff", "name": "staff_credential", "resource": "/staff/credential", "mode": "writable", "pageKind": "list", "fields": [ { "key": "staff_account_identity", "required": true }, { "key": "credential_type", "required": true }, { "key": "credential_no", "required": false }, { "key": "expired_at", "required": false } ] }, { "domain": "user", "name": "user_account", "resource": "/user/account", "mode": "writable", "pageKind": "list", "fields": [ { "key": "username", "required": true }, { "key": "password", "required": true }, { "key": "name", "required": true }, { "key": "phone", "required": false }, { "key": "avatar", "required": false }, { "key": "real_name", "required": false } ] }, { "domain": "user", "name": "user_address", "resource": "/user/address", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "address", "required": true }, { "key": "longitude", "required": false }, { "key": "latitude", "required": false }, { "key": "is_default", "required": false } ] }, { "domain": "user", "name": "user_service_relation", "resource": "/user/service_relation", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "gas_basic_identity", "required": false }, { "key": "delivery_basic_identity", "required": false }, { "key": "staff_account_identity", "required": false } ] }, { "domain": "device", "name": "dev_smart_cylinder_valve", "resource": "/device/dev_smart_cylinder_valve", "mode": "writable", "pageKind": "list", "fields": [ { "key": "device_no", "required": true }, { "key": "model", "required": false }, { "key": "online_status", "required": false }, { "key": "owner_identity", "required": false } ] }, { "domain": "device", "name": "dev_device_binding", "resource": "/device/dev_device_binding", "mode": "writable", "pageKind": "list", "fields": [ { "key": "smart_cylinder_valve_identity", "required": true }, { "key": "user_account_identity", "required": true }, { "key": "effective_at", "required": false }, { "key": "expired_at", "required": false } ] }, { "domain": "device", "name": "dev_telemetry", "resource": "/device/dev_telemetry", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "smart_cylinder_valve_identity", "required": false }, { "key": "recorded_at", "required": false }, { "key": "payload", "required": false } ] }, { "domain": "safety", "name": "saf_rule", "resource": "/safety/saf_rule", "mode": "writable", "pageKind": "list", "fields": [ { "key": "rule_code", "required": true }, { "key": "version_no", "required": false }, { "key": "threshold", "required": false }, { "key": "action", "required": false }, { "key": "gray_scope", "required": false } ] }, { "domain": "safety", "name": "saf_event", "resource": "/safety/saf_event", "mode": "writable", "pageKind": "list", "fields": [ { "key": "event_code", "required": true }, { "key": "level", "required": true }, { "key": "title", "required": true }, { "key": "smart_cylinder_valve_identity", "required": true }, { "key": "sla_at", "required": false } ] }, { "domain": "safety", "name": "saf_inspection", "resource": "/safety/saf_inspection", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "staff_account_identity", "required": true }, { "key": "result", "required": true }, { "key": "evidence_uri", "required": false } ] }, { "domain": "safety", "name": "saf_event_disposal", "resource": "/safety/saf_event/:identity/disposals", "mode": "append_only", "pageKind": "list", "fields": [ { "key": "action", "required": true }, { "key": "reason", "required": true } ] }, { "domain": "ec", "name": "ec_category", "resource": "/ec/ec_category", "mode": "writable", "pageKind": "tree", "fields": [ { "key": "parent_identity", "required": false }, { "key": "name", "required": true }, { "key": "sort_no", "required": false } ] }, { "domain": "ec", "name": "ec_product", "resource": "/ec/ec_product", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_category_identity", "required": true }, { "key": "product_code", "required": true }, { "key": "name", "required": true }, { "key": "price_amount", "required": true }, { "key": "stock_quantity", "required": false } ] }, { "domain": "ec", "name": "ec_product_attribute", "resource": "/ec/ec_product_attribute", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_product_identity", "required": true }, { "key": "name", "required": true }, { "key": "value", "required": true }, { "key": "sort_no", "required": false } ] }, { "domain": "ec", "name": "ec_product_image", "resource": "/ec/ec_product_image", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_product_identity", "required": true }, { "key": "image_uri", "required": true }, { "key": "sort_no", "required": false }, { "key": "is_cover", "required": false } ] }, { "domain": "ec", "name": "ec_cart", "resource": "/ec/ec_cart", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "ec_product_identity", "required": true }, { "key": "quantity", "required": true }, { "key": "selected", "required": false } ] }, { "domain": "ec", "name": "ec_order", "resource": "/ec/ec_order", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "gas_basic_identity", "required": false }, { "key": "delivery_basic_identity", "required": false }, { "key": "order_no", "required": true }, { "key": "total_amount", "required": true } ] }, { "domain": "ec", "name": "ec_order_item", "resource": "/ec/ec_order_item", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_order_identity", "required": true }, { "key": "ec_product_identity", "required": true }, { "key": "product_snapshot", "required": true }, { "key": "quantity", "required": true }, { "key": "sale_amount", "required": true } ] }, { "domain": "ec", "name": "ec_review", "resource": "/ec/ec_review", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_order_identity", "required": true }, { "key": "ec_product_identity", "required": true }, { "key": "user_account_identity", "required": true }, { "key": "score", "required": true }, { "key": "content", "required": true } ] }, { "domain": "finance", "name": "fin_payment", "resource": "/finance/fin_payment", "mode": "writable", "pageKind": "list", "fields": [ { "key": "ec_order_identity", "required": true }, { "key": "channel", "required": true }, { "key": "amount", "required": true }, { "key": "paid_at", "required": false } ] }, { "domain": "finance", "name": "fin_settlement", "resource": "/finance/fin_settlement", "mode": "writable", "pageKind": "list", "fields": [ { "key": "settlement_no", "required": true }, { "key": "subject_type", "required": true }, { "key": "subject_identity", "required": true }, { "key": "period_start", "required": true }, { "key": "period_end", "required": true } ] }, { "domain": "finance", "name": "fin_reconciliation", "resource": "/finance/fin_reconciliation", "mode": "writable", "pageKind": "list", "fields": [ { "key": "channel", "required": true }, { "key": "bill_date", "required": true }, { "key": "difference_amount", "required": true } ] }, { "domain": "content", "name": "cnt_content", "resource": "/content/cnt_content", "mode": "writable", "pageKind": "list", "fields": [ { "key": "content_type", "required": true }, { "key": "title", "required": true }, { "key": "body", "required": true }, { "key": "version_no", "required": false }, { "key": "publish_status", "required": false } ] }, { "domain": "notification", "name": "ntf_template", "resource": "/notification/ntf_template", "mode": "writable", "pageKind": "list", "fields": [ { "key": "template_code", "required": true }, { "key": "channel", "required": true }, { "key": "content", "required": true } ] }, { "domain": "customer_service", "name": "cs_ticket", "resource": "/customer_service/cs_ticket", "mode": "writable", "pageKind": "list", "fields": [ { "key": "user_account_identity", "required": true }, { "key": "ticket_no", "required": true }, { "key": "category", "required": true }, { "key": "priority", "required": true } ] }, { "domain": "platform", "name": "platfrom_account", "resource": "/platform/platfrom_account", "mode": "writable", "pageKind": "list", "fields": [ { "key": "username", "required": true }, { "key": "password", "required": true }, { "key": "display_name", "required": false }, { "key": "avatar", "required": false }, { "key": "platform_role_code", "required": false }, { "key": "phone", "required": false } ] }, { "domain": "platform", "name": "platform_role", "resource": "/platform/platform_role", "mode": "writable", "pageKind": "list", "fields": [ { "key": "role_code", "required": true }, { "key": "name", "required": true }, { "key": "data_scope", "required": true } ] }, { "domain": "platform", "name": "platform_menu", "resource": "/platform/platform_menu", "mode": "writable", "pageKind": "tree", "fields": [ { "key": "parent_identity", "required": false }, { "key": "menu_code", "required": true }, { "key": "name", "required": true }, { "key": "icon", "required": false }, { "key": "path", "required": false }, { "key": "sort_no", "required": false } ] }, { "domain": "wallet", "name": "wallet", "resource": "/wallet/wallet", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "owner_identity", "required": false }, { "key": "balance_amount", "required": false }, { "key": "status", "required": false } ] }, { "domain": "wallet", "name": "wallet_ledger", "resource": "/wallet/wallet_ledger", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "wallet_identity", "required": false }, { "key": "change_amount", "required": false }, { "key": "balance_after", "required": false } ] }, { "domain": "wallet", "name": "wallet_recharge", "resource": "/wallet/wallet_recharge", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "wallet_identity", "required": false }, { "key": "amount", "required": false }, { "key": "status", "required": false } ] }, { "domain": "wallet", "name": "wallet_withdrawal", "resource": "/wallet/wallet_withdrawal", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "wallet_identity", "required": false }, { "key": "amount", "required": false }, { "key": "status", "required": false } ] }, { "domain": "report", "name": "report", "resource": "/report/report", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "report_code", "required": false }, { "key": "name", "required": false }, { "key": "status", "required": false } ] }, { "domain": "report", "name": "report_item", "resource": "/report/report_item", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "report_identity", "required": false }, { "key": "metric_code", "required": false }, { "key": "value", "required": false } ] }, { "domain": "report", "name": "report_metric_snapshot", "resource": "/report/report_metric_snapshot", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "report_identity", "required": false }, { "key": "metric_code", "required": false }, { "key": "value", "required": false }, { "key": "captured_at", "required": false } ] }, { "domain": "audit", "name": "aud_operation_log", "resource": "/audit/aud_operation_log", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "operator_identity", "required": false }, { "key": "action", "required": false }, { "key": "object_identity", "required": false }, { "key": "created_at", "required": false } ] }, { "domain": "audit", "name": "aud_export_log", "resource": "/audit/aud_export_log", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "operator_identity", "required": false }, { "key": "resource_type", "required": false }, { "key": "created_at", "required": false } ] }, { "domain": "audit", "name": "aud_approval", "resource": "/audit/aud_approval", "mode": "readonly", "pageKind": "list", "fields": [ { "key": "operator_identity", "required": false }, { "key": "status", "required": false }, { "key": "handled_at", "required": false } ] } ]; const source = fs.readFileSync('src/api/resources.ts', 'utf8'); const compiled = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 } }).outputText; const resourceModule = { exports: {} }; vm.runInNewContext(compiled, { module: resourceModule, exports: resourceModule.exports }); const resources = resourceModule.exports.resources; const files = (dir) => fs.existsSync(dir) ? fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? files(path.join(dir, entry.name)) : [path.join(dir, entry.name)]) : []; const sameFields = (actual, expected) => Array.isArray(actual) && actual.length === expected.length && actual.every((field, index) => field.key === expected[index].key && Boolean(field.required) === Boolean(expected[index].required)); function checkContracts() { const failures = []; if (!Array.isArray(resources) || resources.length !== contracts.length) failures.push(`catalogue: expected ${contracts.length} resources`); for (const contract of contracts) { const definition = resources.find((resource) => resource.name === contract.name); const label = `${contract.domain}/${contract.name}`; if (!definition || definition.resource !== contract.resource || definition.mode !== contract.mode || definition.pageKind !== contract.pageKind || !sameFields(definition.fields, contract.fields)) failures.push(`${label}: mismatched contract or allowlist`); const requiredIdentity = contract.fields.filter((field) => field.required && field.key.endsWith('_identity')).map((field) => field.key); if (definition && JSON.stringify(definition.requiredIdentities ?? []) !== JSON.stringify(requiredIdentity)) failures.push(`${label}: required identity fields do not match allowlist`); if (contract.name === 'saf_event_disposal') continue; const route = path.join('src/router/routes/modules', contract.domain + '.ts'); if (!fs.existsSync(route) || !fs.readFileSync(route, 'utf8').includes(contract.name)) failures.push(`${label}: missing route`); const page = path.join('src/views', contract.domain, contract.name, contract.pageKind === 'tree' ? 'TreePage.vue' : 'ListPage.vue'); if (!fs.existsSync(page)) failures.push(`${label}: missing view`); if (contract.mode === 'readonly' && (!fs.existsSync(page) || !fs.readFileSync(page, 'utf8').includes('ReadOnlyListPage'))) failures.push(`${label}: readonly page exposes write surface`); } const names = resources.map((resource) => resource.name).sort(); const expectedNames = contracts.map((contract) => contract.name).sort(); if (JSON.stringify(names) !== JSON.stringify(expectedNames)) failures.push('catalogue: resource names do not equal ExpectedResources'); if (resources.some((resource) => resource.fields.some((field) => field.key === 'id' || field.key.endsWith('_id')))) failures.push('catalogue: internal identifier leaked through fields'); const readonlyPage = fs.readFileSync('src/views/shared/ReadOnlyListPage.vue', 'utf8'); if (/(CrudListPage|resourceApi\\.(create|update|archive|updateStatus))/.test(readonlyPage)) failures.push('readonly shared page: contains write surface'); const treePage = fs.readFileSync('src/views/shared/TreePage.vue', 'utf8'); if (!treePage.includes(' resource.name === 'saf_event'); if (!safetyEvent?.detailActions?.some((item) => item.name === 'saf_event_disposal' && item.resource === '/safety/saf_event/:identity/disposals')) failures.push('safety event: missing disposal detail action'); if (files('src/router/routes/modules').some((file) => fs.readFileSync(file, 'utf8').includes('saf_event_disposal')) || fs.existsSync('src/views/safety/saf_event_disposal')) failures.push('saf_event_disposal: must not have independent menu or page'); const crudSource = fs.readFileSync('src/views/shared/CrudListPage.vue', 'utf8'); if (!crudSource.includes("key !== 'id'") || !crudSource.includes("key.endsWith('_id')")) failures.push('detail view: does not remove internal identifiers'); const leakedUiFiles = files('src/api').concat(files('src/views')).filter((file) => /\.(ts|vue)$/.test(file) && !file.endsWith('CrudListPage.vue') && !file.endsWith('ReadOnlyListPage.vue') && !file.endsWith('TreePage.vue')).filter((file) => /\b[A-Za-z][A-Za-z0-9]*_id\b|\bid\b/.test(fs.readFileSync(file, 'utf8'))); if (leakedUiFiles.length) failures.push(`identity leak: ${leakedUiFiles.join(', ')}`); if (/data-index="(?:id|[^" ]+_id)"|\{\{\s*[^}]*\b(?:id|[A-Za-z][A-Za-z0-9]*_id)\b/.test(treePage)) failures.push('tree page: displays internal identifier'); return failures; } const failures = checkContracts(); for (const failure of failures) console.log(failure); if (failures.length) process.exitCode = 1;