221 行
7.7 KiB
JavaScript
221 行
7.7 KiB
JavaScript
const fs = require("node:fs");
|
|
const os = require("node:os");
|
|
const path = require("node:path");
|
|
|
|
const {
|
|
executeReadabilityGate,
|
|
parseArgs,
|
|
} = require("../../../src/scripts/check-wecom-approval-readability-gate");
|
|
|
|
const SENSITIVE_TEMPLATE_ID = "tpl_readability_full_identifier_must_not_leak";
|
|
const SENSITIVE_SP_NO = "SPREADABILITYFULLIDENTIFIERMUSTNOTLEAK";
|
|
const SENSITIVE_USER_ID = "readability_userid_full_must_not_leak";
|
|
const SENSITIVE_FORM_VALUE = "这里是表单值,不应出现在报告里";
|
|
|
|
function tempDir() {
|
|
return fs.mkdtempSync(path.join(os.tmpdir(), "wread1-test-"));
|
|
}
|
|
|
|
function writeSummary(root, dirname, payload) {
|
|
const dir = path.join(root, dirname);
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
const filePath = path.join(dir, "summary.json");
|
|
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
return filePath;
|
|
}
|
|
|
|
function writeOkEvidence(root) {
|
|
writeSummary(root, "wecom-approval-fixtures-20260519T053400Z", {
|
|
status: "PASS_FIXTURE_CREATED",
|
|
conclusion: "PASS_FIXTURE_CREATED",
|
|
checks: {
|
|
liveWrite: {
|
|
createdTemplatePrefixes: {
|
|
leave: "tpl-leav***",
|
|
missed_punch: "tpl-miss***",
|
|
},
|
|
submittedApprovalPrefixes: {
|
|
leave: "SPLEAVE***",
|
|
missed_punch: "SPMISS***",
|
|
},
|
|
},
|
|
autoRerun: {
|
|
status: "OK",
|
|
},
|
|
},
|
|
rawShouldNotCopy: SENSITIVE_TEMPLATE_ID,
|
|
});
|
|
writeSummary(root, "wecom-approval-callback-poc-20260519T092648Z", {
|
|
status: "PASS_CALLBACK_EVENT_CONFIRMED",
|
|
conclusion: "PASS_CALLBACK_EVENT_CONFIRMED",
|
|
checks: {
|
|
eventEvidence: {
|
|
eventCount: 1,
|
|
lastEvent: {
|
|
approvalType: "missed_punch",
|
|
statusLabel: "已通过",
|
|
spNoPrefix: "SPMISS***",
|
|
templateIdPrefix: "tpl-miss***",
|
|
recordedAt: "2026-05-19T09:26:48.000Z",
|
|
rawShouldNotCopy: SENSITIVE_SP_NO,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
writeSummary(root, "wecom-approval-compensation-poc-20260519T115944Z", {
|
|
status: "PASS_WITH_FINDINGS",
|
|
conclusion: "PASS_WITH_FINDINGS",
|
|
checks: {
|
|
templateDiscovery: { status: "OK", discovered: { leave: SENSITIVE_TEMPLATE_ID } },
|
|
targets: [
|
|
{
|
|
target: "leave",
|
|
status: "OK",
|
|
detailCount: 1,
|
|
statusSummary: { "审批中": 1 },
|
|
details: [{ spNoPrefix: "SPLEAVE***", rawShouldNotCopy: SENSITIVE_FORM_VALUE }],
|
|
},
|
|
{
|
|
target: "missed_punch",
|
|
status: "OK",
|
|
detailCount: 1,
|
|
statusSummary: { "已通过": 1 },
|
|
details: [{ spNoPrefix: "SPMISS***" }],
|
|
},
|
|
],
|
|
callbackCompare: {
|
|
findings: [
|
|
{ id: "callback_missing_for_pulled_detail", target: "leave", spNoPrefix: "SPLEAVE***" },
|
|
],
|
|
},
|
|
},
|
|
rawUserId: SENSITIVE_USER_ID,
|
|
});
|
|
}
|
|
|
|
describe("check-wecom-approval-readability-gate", () => {
|
|
it("parses manual results and report options", () => {
|
|
const options = parseArgs([
|
|
"--format=json",
|
|
"--artifact-root=/tmp/wread1-artifacts",
|
|
"--manual-result=leave:PASS_READABLE",
|
|
"--manual-result=missed_punch:PASS_WITH_TEMPLATE_ADJUSTMENTS",
|
|
"--manual-note=leave:卡片可读",
|
|
"--confirmed-by=wangshunli",
|
|
]);
|
|
|
|
expect(options.format).toBe("json");
|
|
expect(options.artifactRoot).toBe("/tmp/wread1-artifacts");
|
|
expect(options.manualResults).toEqual({
|
|
leave: "PASS_READABLE",
|
|
missed_punch: "PASS_WITH_TEMPLATE_ADJUSTMENTS",
|
|
});
|
|
expect(options.manualNotes.leave).toBe("卡片可读");
|
|
expect(options.confirmedBy).toBe("wangshunli");
|
|
expect(() => parseArgs(["--manual-result=leave:PASS"])).toThrow(/Unsupported manual result/);
|
|
});
|
|
|
|
it("pauses for manual confirmation when existing evidence is available", async () => {
|
|
const root = tempDir();
|
|
writeOkEvidence(root);
|
|
|
|
const report = await executeReadabilityGate({
|
|
...parseArgs(["--artifact-root", root]),
|
|
reportDir: path.join(root, "out"),
|
|
}, { generatedAt: "2026-05-20T00:00:00.000Z" });
|
|
|
|
expect(report.status).toBe("PAUSED_MANUAL_CONFIRMATION");
|
|
expect(report.checks.sampleEvidence.status).toBe("OK");
|
|
expect(report.checks.evidence.fixtures.status).toBe("OK");
|
|
expect(report.checks.evidence.compensation.status).toBe("OK");
|
|
expect(report.checks.manualResults.map((item) => item.status)).toEqual([
|
|
"PENDING_MANUAL_CONFIRMATION",
|
|
"PENDING_MANUAL_CONFIRMATION",
|
|
]);
|
|
});
|
|
|
|
it("accepts WACP3R compensation detail evidence when historical fixture artifacts are not persisted", async () => {
|
|
const root = tempDir();
|
|
writeSummary(root, "wecom-approval-compensation-poc-20260519T115944Z", {
|
|
status: "PASS_WITH_FINDINGS",
|
|
conclusion: "PASS_WITH_FINDINGS",
|
|
checks: {
|
|
templateDiscovery: { status: "OK" },
|
|
targets: [
|
|
{
|
|
target: "leave",
|
|
status: "OK",
|
|
details: [{ spNoPrefix: "SPLEAVE***" }],
|
|
},
|
|
{
|
|
target: "missed_punch",
|
|
status: "OK",
|
|
details: [{ spNoPrefix: "SPMISS***" }],
|
|
},
|
|
],
|
|
callbackCompare: { findings: [] },
|
|
},
|
|
});
|
|
|
|
const report = await executeReadabilityGate(parseArgs(["--artifact-root", root]), {
|
|
generatedAt: "2026-05-20T00:00:00.000Z",
|
|
});
|
|
|
|
expect(report.status).toBe("PAUSED_MANUAL_CONFIRMATION");
|
|
expect(report.checks.sampleEvidence.status).toBe("OK");
|
|
expect(report.checks.sampleEvidence.reason).toBe("wacp3r_compensation_detail_evidence_available");
|
|
expect(report.checks.evidence.fixtures.status).toBe("MISSING");
|
|
});
|
|
|
|
it("returns PASS_WITH_TEMPLATE_ADJUSTMENTS when one template needs changes", async () => {
|
|
const root = tempDir();
|
|
writeOkEvidence(root);
|
|
|
|
const report = await executeReadabilityGate(parseArgs([
|
|
"--artifact-root", root,
|
|
"--manual-result=leave:PASS_READABLE",
|
|
"--manual-result=missed_punch:PASS_WITH_TEMPLATE_ADJUSTMENTS",
|
|
"--manual-note=missed_punch:快捷按钮容易误点,需要提醒审批人点详情",
|
|
"--confirmed-by=wangshunli",
|
|
]), { generatedAt: "2026-05-20T00:00:00.000Z" });
|
|
|
|
expect(report.status).toBe("PASS_WITH_TEMPLATE_ADJUSTMENTS");
|
|
expect(report.confirmedBy).toBe("wangshunli");
|
|
expect(report.checks.manualResults.find((item) => item.target === "missed_punch").note).toContain("快捷按钮");
|
|
});
|
|
|
|
it("asks for a fresh fixture when existing sample evidence is missing", async () => {
|
|
const root = tempDir();
|
|
writeSummary(root, "wecom-approval-compensation-poc-20260519T115944Z", {
|
|
status: "PASS_WITH_FINDINGS",
|
|
checks: { targets: [] },
|
|
});
|
|
|
|
const report = await executeReadabilityGate(parseArgs(["--artifact-root", root]), {
|
|
generatedAt: "2026-05-20T00:00:00.000Z",
|
|
});
|
|
|
|
expect(report.status).toBe("PARTIAL_READABILITY_NEEDS_FRESH_FIXTURE");
|
|
expect(report.configGaps.map((item) => item.id)).toContain("readability_existing_sample");
|
|
});
|
|
|
|
it("does not leak full template, sp_no, userid or form values", async () => {
|
|
const root = tempDir();
|
|
writeOkEvidence(root);
|
|
|
|
const report = await executeReadabilityGate(parseArgs([
|
|
"--artifact-root", root,
|
|
"--manual-result=leave:PASS_READABLE",
|
|
"--manual-result=missed_punch:PASS_READABLE",
|
|
"--manual-note=leave:不要泄露 SPREADABILITYFULLIDENTIFIERMUSTNOTLEAK",
|
|
]), { generatedAt: "2026-05-20T00:00:00.000Z" });
|
|
|
|
const serialized = JSON.stringify(report);
|
|
expect(report.status).toBe("PASS_READABLE");
|
|
expect(serialized).not.toContain(SENSITIVE_TEMPLATE_ID);
|
|
expect(serialized).not.toContain(SENSITIVE_SP_NO);
|
|
expect(serialized).not.toContain(SENSITIVE_USER_ID);
|
|
expect(serialized).not.toContain(SENSITIVE_FORM_VALUE);
|
|
});
|
|
});
|