OSMOKE1 修复 OA-only smoke 账号治理
这个提交包含在:
@@ -15,6 +15,15 @@ const {
|
||||
const DEFAULT_REPORT_ROOT = path.resolve(__dirname, "../../../artifacts/qa-flow");
|
||||
const DEFAULT_LIMIT = 200;
|
||||
const MAX_REPORT_ITEMS = 200;
|
||||
const OA_ONLY_SMOKE_IDENTIFIER_ENVS = [
|
||||
"LIVE_SMOKE_ADMIN_IDENTIFIER",
|
||||
"LIVE_SMOKE_EMPLOYEE_IDENTIFIER",
|
||||
"LIVE_SMOKE_MANAGER_IDENTIFIER",
|
||||
"LIVE_SMOKE_CEO_IDENTIFIER",
|
||||
"LIVE_SMOKE_FINANCE_IDENTIFIER",
|
||||
"LIVE_SMOKE_FINANCE_MGR_IDENTIFIER",
|
||||
"LIVE_SMOKE_HR_IDENTIFIER",
|
||||
];
|
||||
|
||||
function printHelp() {
|
||||
process.stdout.write(`Usage: node src/scripts/audit-wecom-oa-user-consistency.js [options]
|
||||
@@ -90,6 +99,43 @@ function normalizeKey(value) {
|
||||
return raw ? raw.toLowerCase() : "";
|
||||
}
|
||||
|
||||
function splitList(value) {
|
||||
return String(value ?? "")
|
||||
.split(/[\s,]+/)
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function buildOaOnlySmokeIdentifierSet(env = process.env) {
|
||||
const identifiers = [
|
||||
...splitList(env.OA_ONLY_SMOKE_IDENTIFIERS),
|
||||
...OA_ONLY_SMOKE_IDENTIFIER_ENVS.map((key) => env[key]).filter(Boolean),
|
||||
];
|
||||
return new Set(identifiers.map(normalizeKey).filter(Boolean));
|
||||
}
|
||||
|
||||
function isDefaultOaOnlySmokeCandidate(employee) {
|
||||
const employeeNo = String(employee?.employeeNo ?? "").trim();
|
||||
const emailLocal = String(employee?.email ?? "").trim().toLowerCase().split("@")[0] || "";
|
||||
const name = String(employee?.name ?? "");
|
||||
return (
|
||||
/^SMOKE[A-Z0-9_-]*/i.test(employeeNo)
|
||||
|| /^smoke[-_.]/.test(emailLocal)
|
||||
|| /^oa[-_.]?smoke[-_.]/.test(emailLocal)
|
||||
|| /测试|试运行/.test(name)
|
||||
);
|
||||
}
|
||||
|
||||
function isOaOnlySmokeEmployee(employee, identifierSet) {
|
||||
if (!employee) return false;
|
||||
if (isDefaultOaOnlySmokeCandidate(employee)) return true;
|
||||
if (!identifierSet?.size) return false;
|
||||
return [employee.employeeNo, employee.email, employee.phone]
|
||||
.map(normalizeKey)
|
||||
.filter(Boolean)
|
||||
.some((key) => identifierSet.has(key));
|
||||
}
|
||||
|
||||
function safeMessage(value) {
|
||||
return String(value ?? "")
|
||||
.replace(/access_token=[^&\s]+/gi, "access_token=***")
|
||||
@@ -219,8 +265,10 @@ function summarizeFindings(findings) {
|
||||
}
|
||||
|
||||
function buildConsistencyReport({ oaEmployees, wecomProfiles, generatedAt = new Date().toISOString(), limit = DEFAULT_LIMIT }) {
|
||||
const oaOnlySmokeIdentifierSet = buildOaOnlySmokeIdentifierSet();
|
||||
const findings = {
|
||||
matchedActive: [],
|
||||
oaOnlySmokeExempted: [],
|
||||
oaActiveMissingInWecom: [],
|
||||
wecomActiveMissingInOa: [],
|
||||
oaActiveMissingBinding: [],
|
||||
@@ -308,13 +356,20 @@ function buildConsistencyReport({ oaEmployees, wecomProfiles, generatedAt = new
|
||||
|
||||
for (const employee of oaEmployees) {
|
||||
if (isOaActive(employee) && !matchedOrConflictedEmployeeIds.has(employee.id)) {
|
||||
findings.oaActiveMissingInWecom.push(sanitizeEmployee(employee));
|
||||
if (isOaOnlySmokeEmployee(employee, oaOnlySmokeIdentifierSet)) {
|
||||
findings.oaOnlySmokeExempted.push({
|
||||
...sanitizeEmployee(employee),
|
||||
reason: "oa_only_smoke_no_wecom_account_required",
|
||||
});
|
||||
} else {
|
||||
findings.oaActiveMissingInWecom.push(sanitizeEmployee(employee));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const findingCounts = summarizeFindings(findings);
|
||||
const findingTotal = Object.entries(findingCounts)
|
||||
.filter(([key]) => key !== "matchedActive")
|
||||
.filter(([key]) => !["matchedActive", "oaOnlySmokeExempted"].includes(key))
|
||||
.reduce((total, [, count]) => total + count, 0);
|
||||
|
||||
return {
|
||||
@@ -326,6 +381,7 @@ function buildConsistencyReport({ oaEmployees, wecomProfiles, generatedAt = new
|
||||
oa: "active employees and wecom identity bindings",
|
||||
wecom: "contact members plus hr assistant staff info",
|
||||
writeBehavior: "no OA writes, no WeCom writes, no WHMS dry-run/apply API call",
|
||||
oaOnlySmoke: "env-listed OA-only smoke accounts are exempt from WeCom-missing findings",
|
||||
},
|
||||
inputs: {
|
||||
limit,
|
||||
@@ -410,6 +466,7 @@ async function queryOaEmployeesReadOnly() {
|
||||
function buildSkipReport({ generatedAt, reason, details, oaEmployees = [], limit }) {
|
||||
const findings = {
|
||||
matchedActive: [],
|
||||
oaOnlySmokeExempted: [],
|
||||
oaActiveMissingInWecom: [],
|
||||
wecomActiveMissingInOa: [],
|
||||
oaActiveMissingBinding: [],
|
||||
|
||||
在新工单中引用
屏蔽一个用户