Files
gongxue-base/scripts/sms-rate-limit-contract-test.js
2026-07-12 19:26:57 +08:00

28 lines
1.6 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs';
const migration = fs.readFileSync('supabase/migrations/202607120012_sms_send_reservation_limits.sql', 'utf8');
const routes = fs.readFileSync('apps/api/src/features/auth/routes.ts', 'utf8');
const limits = fs.readFileSync('apps/api/src/features/auth/sms-limits.ts', 'utf8');
const nginx = fs.readFileSync('scripts/deploy/nginx/tjszsb.com.conf.example', 'utf8');
const taroAuth = fs.readFileSync('apps/taro/src/services/auth.ts', 'utf8');
assert.match(migration, /unique index[^;]+idx_sms_codes_active_phone_reservation[\s\S]+status in \('pending', 'sent'\)/i);
assert.match(migration, /app_private\.sms_send_rate_limits/);
assert.match(migration, /primary key \(tenant_id, dimension, scope_hash, bucket_start\)/);
assert.match(limits, /pg_advisory_xact_lock/);
assert.match(limits, /SMS_TENANT_DAILY_LIMIT/);
assert.match(limits, /SMS_PHONE_DAILY_LIMIT/);
assert.match(limits, /SMS_IP_HOURLY_LIMIT/);
assert.match(limits, /SMS_DEVICE_HOURLY_LIMIT/);
assert.match(limits, /createHmac\('sha256', config\.authCodePepper\)/);
assert.match(routes, /reserveSmsSend/);
assert.ok(routes.indexOf('reserveSmsSend') < routes.indexOf('provider.send'), 'SMS quota must be reserved before provider cost is incurred');
assert.match(nginx, /limit_req_zone \$binary_remote_addr zone=tiku_sms_send/);
assert.match(nginx, /location = \/api\/auth\/sms\/send/);
assert.match(nginx, /limit_req zone=tiku_sms_send/);
assert.match(nginx, /proxy_set_header X-Forwarded-For \$remote_addr;/);
assert.match(taroAuth, /deviceId: smsDeviceId\(\)/);
console.log('[PASS] SMS atomic quota and proxy rate-limit contract');