实现(08-10-production-employee-smoke-break-glass-reset): 增加员工Smoke受控重置工具
这个提交包含在:
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户