import assert from 'node:assert/strict'; import pg from 'pg'; import { spawn } from 'node:child_process'; const databaseUrl = process.env.DATABASE_URL || 'postgresql://postgres:postgres@127.0.0.1:54322/postgres'; const ids = { tenant: '00000000-0000-0000-0000-00000000aa01', auditLog: '00000000-0000-0000-0000-00000000aa02', }; function runWorkerOnce() { const child = spawn(process.execPath, ['apps/worker/dist/apps/worker/src/index.js', '--once', '--job', 'platform-audit-alerts'], { cwd: process.cwd(), env: { ...process.env, DATABASE_URL: databaseUrl, WORKER_PLATFORM_AUDIT_ALERT_BATCH_SIZE: '20', WORKER_PLATFORM_AUDIT_ALERT_LOOKBACK_DAYS: '30', WORKER_PLATFORM_AUDIT_ALERT_ID: 'platform-audit-alert-worker-test', }, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true, }); let output = ''; child.stdout.on('data', chunk => { output += chunk.toString(); }); child.stderr.on('data', chunk => { output += chunk.toString(); }); return new Promise((resolve, reject) => { child.on('error', reject); child.on('exit', code => { try { assert.equal(code, 0, `worker should exit 0\n${output}`); assert.match(output, /platform-audit-alerts batch processed=\d+/, 'worker output should include audit alert summary'); resolve(output); } catch (error) { reject(error); } }); }); } async function cleanup(pool) { await pool.query('delete from public.platform_audit_alerts where tenant_id = $1 or audit_log_id = $2', [ids.tenant, ids.auditLog]); await pool.query('delete from public.audit_logs where tenant_id = $1 or id = $2', [ids.tenant, ids.auditLog]); await pool.query('delete from public.tenant_billing_profiles where tenant_id = $1', [ids.tenant]); await pool.query('delete from public.tenant_domains where tenant_id = $1', [ids.tenant]); await pool.query('delete from public.tenants where id = $1', [ids.tenant]); } async function createAuditLog(pool) { await pool.query( ` insert into public.tenants (id, slug, name, legal_name, status, mode, billing_status, metadata) values ($1, 'platform-audit-alert-worker', '平台审计告警租户', '平台审计告警有限公司', 'active', 'saas', 'active', '{"source":"platform-audit-alert-worker-test"}'::jsonb) `, [ids.tenant], ); await pool.query( ` insert into public.audit_logs ( id, tenant_id, actor_user_id, action, target_type, target_id, details, ip_address, user_agent, created_at ) values ( $1, $2::uuid, null, 'platform.tenant.status_updated', 'tenant', $3, '{"status":"suspended","reason":"integration alert","accessToken":"must-not-leak","nested":{"password":"must-not-leak"}}'::jsonb, '127.0.0.1', 'platform-audit-alert-worker-test', now() ) `, [ids.auditLog, ids.tenant, ids.tenant], ); } async function main() { const pool = new pg.Pool({ connectionString: databaseUrl }); try { await cleanup(pool); await createAuditLog(pool); const firstOutput = await runWorkerOnce(); assert.match(firstOutput, /created=\d+/, 'worker should create alert candidates'); const alerts = await pool.query( ` select a.id, a.status, a.severity, a.action, a.target_type, a.target_id, a.details, r.code as rule_code from public.platform_audit_alerts a join public.platform_audit_alert_rules r on r.id = a.rule_id where a.tenant_id = $1 and a.audit_log_id = $2 `, [ids.tenant, ids.auditLog], ); assert.equal(alerts.rowCount, 1, 'worker should create one alert for the audit log'); assert.equal(alerts.rows[0].status, 'open', 'worker alert should start open'); assert.equal(alerts.rows[0].severity, 'high', 'tenant status changes should be high severity'); assert.equal(alerts.rows[0].rule_code, 'platform_tenant_status_changed', 'worker should match default tenant status rule'); assert.equal(alerts.rows[0].details?.workerId, 'platform-audit-alert-worker-test', 'alert should record worker id'); assert.equal(alerts.rows[0].details?.auditDetails?.accessToken, '[REDACTED]', 'alert should redact token-like audit details'); assert.equal(alerts.rows[0].details?.auditDetails?.nested?.password, '[REDACTED]', 'alert should redact nested password-like audit details'); assert.ok(!JSON.stringify(alerts.rows[0].details).includes('must-not-leak'), 'alert details must not leak sensitive audit values'); const audit = await pool.query( ` select action, target_type, target_id, details from public.audit_logs where tenant_id = $1 and action = 'platform.audit.alert_created' order by created_at desc limit 1 `, [ids.tenant], ); assert.equal(audit.rows[0]?.target_type, 'platform_audit_alert', 'worker should audit alert creation'); assert.equal(audit.rows[0]?.details?.ruleCode, 'platform_tenant_status_changed', 'worker audit should include rule code'); await runWorkerOnce(); const count = await pool.query( ` select count(*)::integer as count from public.platform_audit_alerts where tenant_id = $1 and audit_log_id = $2 `, [ids.tenant, ids.auditLog], ); assert.equal(Number(count.rows[0]?.count), 1, 'worker should be idempotent'); console.log('Platform audit alert worker integration test complete.'); } finally { await cleanup(pool).catch(() => {}); await pool.end(); } } main().catch(error => { console.error(error); process.exit(1); });