实现(08-10-production-employee-smoke-break-glass-reset): 增加员工Smoke受控重置工具
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-10 21:01:59 +08:00
父节点 b807762c52
当前提交 ec68256588
共修改 10 个文件,包含 1310 行新增和 0 行删除
@@ -1,4 +1,5 @@
const {
applyTarget,
isSafeOaOnlySmokeTarget,
isSmokeLikeValue,
normalizeRoleList,
@@ -85,4 +86,56 @@ describe("repair-oa-only-smoke-accounts", () => {
expect(normalizeRoleList(["admin", "admin", "invalid", "employee"])).toEqual(["admin", "employee"]);
expect(process.env.OA_ONLY_SMOKE_REPAIR_APPLY).toBeUndefined();
});
it("applies only lifecycle, login-lock, token, missing-role, and audit repairs", async () => {
const current = row({
status: "archived",
employmentStatus: "inactive",
archived: true,
roles: ["employee"],
});
const planned = planForTarget(target(), current);
const client = {
query: vi.fn(async (sql) => {
const text = String(sql);
if (text.includes("SELECT")) {
return {
rows: [
{
id: current.id,
employee_no: current.employeeNo,
name: current.name,
email: current.email,
phone: current.phone,
status: "active",
employment_status: "active",
archived: false,
login_failed_count: 0,
has_login_failed_first_at: false,
login_locked_until: null,
roles: ["admin", "employee"],
active_auth_sessions: 0,
},
],
};
}
return { rows: [] };
}),
};
await expect(
applyTarget(client, target(), planned, new Date("2026-08-10T00:00:00.000Z")),
).resolves.toMatchObject({ result: "applied" });
const sql = client.query.mock.calls.map(([statement]) => String(statement)).join("\n");
expect(sql).toContain("token_version = token_version + 1");
expect(sql).toContain("INSERT INTO employee_roles");
expect(sql).toContain("ON CONFLICT (employee_id, role_code) DO NOTHING");
expect(sql).toContain("INSERT INTO employee_lifecycle_events");
expect(sql).not.toContain("DELETE FROM employee_roles");
expect(sql).not.toContain("password_hash");
expect(sql).not.toMatch(/(?:UPDATE|INSERT\s+INTO|DELETE\s+FROM)\s+auth_sessions/iu);
expect(sql).not.toMatch(/(?:UPDATE|INSERT\s+INTO|DELETE\s+FROM)\s+password_reset_codes/iu);
expect(sql).not.toMatch(/(?:UPDATE|INSERT\s+INTO|DELETE\s+FROM)\s+email_login_codes/iu);
});
});