const test = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const deployPath = path.resolve(__dirname, '../../../deploy.sh') const deployScript = fs.readFileSync(deployPath, 'utf8') test('标准部署在 build/up 前必须通过报废迁移预检', () => { const gateCall = deployScript.lastIndexOf('\nrun_disposal_migration_precheck\n') const buildCall = deployScript.indexOf('"${COMPOSE_CMD[@]}" build') const upCall = deployScript.indexOf('"${COMPOSE_CMD[@]}" up -d --remove-orphans') assert.ok(gateCall > 0, '部署脚本必须调用迁移前预检') assert.ok(buildCall > gateCall, '预检必须早于镜像构建') assert.ok(upCall > gateCall, '预检必须早于容器更新/迁移') assert.match( deployScript, /backend\/prisma\/migrations\/20260714_asset_permissions_disposal_dingtalk\/precheck\.sql/ ) }) test('预检只连接固定资产 MySQL,不在命令行暴露密码', () => { assert.match(deployScript, /MYSQL_CONTAINER="equipment-mysql"/) assert.match(deployScript, /--defaults-extra-file="\$defaults_file"/) assert.doesNotMatch(deployScript, /mysql\s+[^\n]*--password=/) assert.doesNotMatch(deployScript, /shebeiguanli|\/opt\/shebeiguanli/) assert.doesNotMatch( deployScript, /LEGACY_CONTAINERS|record_legacy_container_statuses|verify_legacy_container_statuses/ ) }) test('无法确认或存在未核对报废单时默认阻断,仅允许本次显式确认', () => { assert.ok( deployScript.includes( "SELECT id, status, equipment_id, DATE_FORMAT(updated_at, '%Y-%m-%dT%H:%i:%s.%f') FROM disposal_record WHERE status IN ('pending', 'approved') ORDER BY id, status, equipment_id, updated_at;" ), '预检必须稳定读取待审批和已审批报废单的指纹字段' ) assert.match(deployScript, /printf '%s\\n' "\$active_rows" \| sha256sum/) assert.match( deployScript, /CONFIRM_ACTIVE_DISPOSALS_REVIEWED" != "\$active_fingerprint"/ ) assert.match(deployScript, /已默认阻止部署/) }) test('未完成报废资产树存在环或深度达到 100 时禁止 override', () => { const anomalyBlock = deployScript.indexOf('if [ "$tree_anomaly_count" -gt 0 ]') const overrideCheck = deployScript.indexOf( 'if [ "$CONFIRM_ACTIVE_DISPOSALS_REVIEWED" != "$active_fingerprint" ]' ) assert.match(deployScript, /WHERE cycle_detected = 1 OR depth >= 100;/) assert.ok(anomalyBlock > 0, '必须对资产树异常数量做硬阻断') assert.ok(overrideCheck > anomalyBlock, '资产树异常阻断必须早于指纹 override') assert.match(deployScript, /不允许通过确认指纹绕过/) })