forked from wangziqi/gongxue-base
fix: require configured production SMS provider in DB
This commit is contained in:
@@ -212,6 +212,57 @@ assert.ok(
|
|||||||
pnvsTemplateParamWarning.payload.checks?.some(item => item.id === 'db.auth.aliyun-pnvs.template_param' && item.status === 'warn'),
|
pnvsTemplateParamWarning.payload.checks?.some(item => item.id === 'db.auth.aliyun-pnvs.template_param' && item.status === 'warn'),
|
||||||
'readiness should warn when PNVS templateParam lacks ##code##',
|
'readiness should warn when PNVS templateParam lacks ##code##',
|
||||||
);
|
);
|
||||||
|
assert.ok(
|
||||||
|
pnvsTemplateParamWarning.payload.checks?.some(item => item.id === 'db.auth_sms_provider_configured' && item.status === 'pass'),
|
||||||
|
'readiness should pass when AUTH_SMS_PROVIDER has a matching PNVS provider row',
|
||||||
|
);
|
||||||
|
|
||||||
|
const mismatchedSmsProviderFixture = runReadiness(
|
||||||
|
`
|
||||||
|
NODE_ENV=production
|
||||||
|
DATABASE_URL=postgresql://prod_user:prod_password@db.prod.internal:5432/tiku
|
||||||
|
CORS_ORIGIN=https://student.gongxue100.com,https://tenant-admin.gongxue100.com,https://platform-admin.gongxue100.com
|
||||||
|
AUTH_SMS_PROVIDER=aliyun-pnvs
|
||||||
|
AUTH_CODE_PEPPER=${strongSecretA}
|
||||||
|
AUTH_SESSION_SECRET=${strongSecretB}
|
||||||
|
AUTH_JWT_JWKS_URL=https://auth.gongxue100.com/auth/v1/.well-known/jwks.json
|
||||||
|
AUTH_JWT_ISSUER=https://auth.gongxue100.com/auth/v1
|
||||||
|
ALLOW_LEGACY_AUTH_HEADERS=false
|
||||||
|
ALLOW_PLATFORM_ADMIN_KEY=false
|
||||||
|
PLATFORM_ADMIN_API_KEY=${strongSecretC}
|
||||||
|
STORAGE_DEFAULT_PROVIDER=aliyun_oss
|
||||||
|
STORAGE_DEFAULT_BUCKET=tiku-assets
|
||||||
|
STORAGE_REQUIRE_TENANT_PREFIX=true
|
||||||
|
ALIYUN_OSS_REGION=cn-hangzhou
|
||||||
|
ALIYUN_OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com
|
||||||
|
ALIYUN_OSS_ACCESS_KEY_ID=LTAI_READINESS_TEST_ONLY
|
||||||
|
ALIYUN_OSS_ACCESS_KEY_SECRET=aliyun-readiness-secret-placeholder
|
||||||
|
WORKER_ASSET_SECURITY_SCANNER=metadata_rules,http
|
||||||
|
WORKER_ASSET_SECURITY_SCAN_HTTP_ENDPOINT=https://scanner.gongxue100.com/api/scan
|
||||||
|
WORKER_ASSET_SECURITY_SCAN_HTTP_TOKEN=s3cure-asset-scanner-token-2026-06-29-stuvwx
|
||||||
|
WORKER_ASSET_SECURITY_SCAN_FAIL_OPEN=false
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
providerRows: [
|
||||||
|
{
|
||||||
|
source: 'auth',
|
||||||
|
tenantId: 'tenant-aliyun',
|
||||||
|
provider: 'aliyun',
|
||||||
|
configPublic: {
|
||||||
|
signName: '短信签名',
|
||||||
|
templateCode: 'SMS_123456789',
|
||||||
|
endpoint: 'https://dysmsapi.aliyuncs.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.notEqual(mismatchedSmsProviderFixture.status, 0, 'readiness should fail when AUTH_SMS_PROVIDER has no matching active provider row');
|
||||||
|
assert.ok(
|
||||||
|
mismatchedSmsProviderFixture.payload.checks?.some(item => item.id === 'db.auth_sms_provider_configured' && item.status === 'blocker'),
|
||||||
|
'readiness should block env/provider mismatch',
|
||||||
|
);
|
||||||
|
|
||||||
const unsafeProviderFixture = runReadiness(
|
const unsafeProviderFixture = runReadiness(
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -171,6 +171,32 @@ function providerIn(provider, aliases) {
|
|||||||
return aliases.has(normalizeProvider(provider));
|
return aliases.has(normalizeProvider(provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function currentSmsProviderAliases() {
|
||||||
|
const provider = normalizeProvider(env('AUTH_SMS_PROVIDER', 'mock')).replace(/_/g, '-');
|
||||||
|
if (AUTH_PROVIDER_ALIASES.aliyunPnvs.has(provider)) return { provider: 'aliyun-pnvs', aliases: AUTH_PROVIDER_ALIASES.aliyunPnvs };
|
||||||
|
if (AUTH_PROVIDER_ALIASES.aliyun.has(provider)) return { provider: 'aliyun', aliases: AUTH_PROVIDER_ALIASES.aliyun };
|
||||||
|
if (AUTH_PROVIDER_ALIASES.tencent.has(provider)) return { provider: 'tencent', aliases: AUTH_PROVIDER_ALIASES.tencent };
|
||||||
|
return { provider, aliases: new Set([provider]) };
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateActiveSmsProviderRows(rows, sourceLabel = 'database') {
|
||||||
|
const expected = currentSmsProviderAliases();
|
||||||
|
if (!PRODUCTION_SMS_PROVIDERS.has(normalizeProvider(env('AUTH_SMS_PROVIDER', 'mock')))) return;
|
||||||
|
const activeRows = rows.filter(row => row.source === 'auth' && providerIn(row.provider, expected.aliases));
|
||||||
|
if (activeRows.length === 0) {
|
||||||
|
block('db.auth_sms_provider_configured', 'AUTH_SMS_PROVIDER must have a matching active/testing tenant_auth_providers row', {
|
||||||
|
provider: expected.provider,
|
||||||
|
source: sourceLabel,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pass('db.auth_sms_provider_configured', 'AUTH_SMS_PROVIDER has matching active/testing tenant auth provider rows', {
|
||||||
|
provider: expected.provider,
|
||||||
|
count: activeRows.length,
|
||||||
|
source: sourceLabel,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function validateProviderUrl({
|
function validateProviderUrl({
|
||||||
id,
|
id,
|
||||||
value,
|
value,
|
||||||
@@ -457,6 +483,7 @@ function validateProviderConfigRows(inputRows) {
|
|||||||
warn('db.provider_fixture.empty', 'Provider config fixture did not contain any rows');
|
warn('db.provider_fixture.empty', 'Provider config fixture did not contain any rows');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
validateActiveSmsProviderRows(rows, 'fixture');
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
const secretPaths = findSecretLikePaths(row.config_public || {});
|
const secretPaths = findSecretLikePaths(row.config_public || {});
|
||||||
if (secretPaths.length > 0) {
|
if (secretPaths.length > 0) {
|
||||||
@@ -793,6 +820,7 @@ async function validateDatabase() {
|
|||||||
if (publicSecretRows.rows.every(row => findSecretLikePaths(row.config_public || {}).length === 0)) {
|
if (publicSecretRows.rows.every(row => findSecretLikePaths(row.config_public || {}).length === 0)) {
|
||||||
pass('db.provider_public_config', 'Active provider public configs do not contain secret-like keys');
|
pass('db.provider_public_config', 'Active provider public configs do not contain secret-like keys');
|
||||||
}
|
}
|
||||||
|
validateActiveSmsProviderRows(publicSecretRows.rows, 'database');
|
||||||
|
|
||||||
const activePlatformAdminRows = await pool.query(`
|
const activePlatformAdminRows = await pool.query(`
|
||||||
select id, username, phone, auth_user_id
|
select id, username, phone, auth_user_id
|
||||||
|
|||||||
Reference in New Issue
Block a user