R30-1 R30-9: 建立零人工发布门禁并补齐高频回归

这个提交包含在:
2026-03-23 10:00:26 +08:00
父节点 c17a72830c
当前提交 994d98e74c
共修改 22 个文件,包含 1189 行新增和 41 行删除
+141
查看文件
@@ -0,0 +1,141 @@
require('dotenv/config');
const { getConfig } = require('../config');
function assertCondition(condition, message) {
if (!condition) {
throw new Error(message);
}
}
function formatList(items) {
return items.filter(Boolean).join(', ');
}
function evaluateWecom(config) {
if (!config.wecomEnabled) {
return { state: 'disabled', detail: '企业微信入口未启用', checks: [] };
}
const missing = [];
if (!String(config.wecomCorpId ?? '').trim()) missing.push('WECOM_CORP_ID');
if (!String(config.wecomAgentId ?? '').trim()) missing.push('WECOM_AGENT_ID');
if (!String(config.wecomAgentSecret ?? '').trim()) missing.push('WECOM_AGENT_SECRET');
if (config.wecomOauthEnabled && !String(config.wecomRedirectUri ?? '').trim()) missing.push('WECOM_REDIRECT_URI');
if (config.wecomEntryEnabled && !String(config.wecomAllowedReturnHosts ?? '').trim()) missing.push('WECOM_ALLOWED_RETURN_HOSTS');
assertCondition(missing.length === 0, `企业微信配置不完整:${formatList(missing)}`);
if (!config.wecomEntryEnabled || !config.wecomOauthEnabled) {
return {
state: 'degraded',
detail: `企业微信基础配置已启用,但入口=${config.wecomEntryEnabled ? 'on' : 'off'} oauth=${config.wecomOauthEnabled ? 'on' : 'off'}`,
checks: [`corpId=${config.wecomCorpId}`, `agentId=${config.wecomAgentId}`],
};
}
return {
state: 'ready',
detail: '企业微信入口与免登配置齐全',
checks: [`corpId=${config.wecomCorpId}`, `agentId=${config.wecomAgentId}`, `redirectUri=${config.wecomRedirectUri}`],
};
}
function evaluateEmail(config) {
if (!config.emailEnabled) {
return { state: 'disabled', detail: '企业邮箱 SMTP 未启用', checks: [] };
}
const missing = [];
if (!String(config.emailFrom ?? '').trim()) missing.push('EMAIL_FROM');
if (!String(config.smtpHost ?? '').trim()) missing.push('SMTP_HOST');
if (!Number.isFinite(Number(config.smtpPort)) || Number(config.smtpPort) <= 0) missing.push('SMTP_PORT');
if (String(config.smtpUser ?? '').trim() && !String(config.smtpPass ?? '').trim()) missing.push('SMTP_PASS');
assertCondition(missing.length === 0, `SMTP 配置不完整:${formatList(missing)}`);
return {
state: 'ready',
detail: 'SMTP 基础配置齐全(仅做配置契约校验,不发真实邮件)',
checks: [`from=${config.emailFrom}`, `host=${config.smtpHost}`, `port=${config.smtpPort}`, `secure=${config.smtpSecure}`],
};
}
function evaluateOcr(config) {
const provider = String(config.ocrProvider ?? 'off').trim();
if (!provider || provider === 'off') {
return { state: 'disabled', detail: 'OCR provider 已关闭', checks: [] };
}
if (provider === 'mock') {
return { state: 'mock', detail: 'OCR 使用 mock provider', checks: [`provider=${provider}`] };
}
if (provider === 'tencent') {
const missing = [];
if (!String(config.tencentSecretId ?? '').trim()) missing.push('TENCENT_SECRET_ID');
if (!String(config.tencentSecretKey ?? '').trim()) missing.push('TENCENT_SECRET_KEY');
assertCondition(missing.length === 0, `腾讯 OCR 配置不完整:${formatList(missing)}`);
return {
state: 'ready',
detail: '腾讯 OCR 配置齐全',
checks: [`provider=${provider}`, `region=${config.tencentOcrRegion}`],
};
}
return {
state: 'custom',
detail: `OCR provider=${provider},请确认对应适配器契约`,
checks: [`provider=${provider}`],
};
}
function evaluateBridge(config) {
if (!config.imNotifierEnabled) {
return { state: 'disabled', detail: '消息回流桥接未启用', checks: [] };
}
const missing = [];
if (!String(config.appOrigin ?? '').trim()) missing.push('APP_ORIGIN');
if (!String(config.fieldEncryptionKey ?? '').trim()) missing.push('FIELD_ENCRYPTION_KEY');
assertCondition(missing.length === 0, `消息桥接配置不完整:${formatList(missing)}`);
return {
state: 'ready',
detail: '消息回流桥接配置齐全',
checks: [`appOrigin=${config.appOrigin}`],
};
}
function printSection(name, section) {
const tag = section.state === 'ready' || section.state === 'mock' || section.state === 'disabled' || section.state === 'custom'
? 'PASS'
: section.state === 'degraded'
? 'WARN'
: 'INFO';
console.log(`[${tag}] ${name}: ${section.detail}`);
for (const line of section.checks ?? []) {
console.log(` - ${line}`);
}
}
function main() {
const config = getConfig();
console.log('[R30] 开始 external deps smoke');
const sections = {
wecom: evaluateWecom(config),
email: evaluateEmail(config),
ocr: evaluateOcr(config),
bridge: evaluateBridge(config),
};
printSection('企业微信', sections.wecom);
printSection('SMTP 邮件', sections.email);
printSection('OCR', sections.ocr);
printSection('消息桥接', sections.bridge);
console.log('[R30][PASS] external deps smoke 通过');
}
main();