修复生产回填审计标识(07-28-ceo-finance-fallback)
这个提交包含在:
@@ -215,12 +215,12 @@ async function execute(options, pool = new Pool({ connectionString: process.env.
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO audit_logs
|
||||
(request_id, actor_id, action, target_type, target_id, ip_address, user_agent, extra)
|
||||
(id, request_id, actor_id, action, target_type, target_id, ip_address, user_agent, extra)
|
||||
VALUES
|
||||
($1, $2::uuid, 'APPROVAL_RULE_UPDATED', 'approval_rule', $3::uuid, NULL,
|
||||
'controlled-script/07-28-ceo-finance-fallback', $4::jsonb)
|
||||
($1::uuid, $2, $3::uuid, 'APPROVAL_RULE_UPDATED', 'approval_rule', $4::uuid, NULL,
|
||||
'controlled-script/07-28-ceo-finance-fallback', $5::jsonb)
|
||||
`,
|
||||
[requestId, admins[0].id, item.id, JSON.stringify({
|
||||
[crypto.randomUUID(), requestId, admins[0].id, item.id, JSON.stringify({
|
||||
task: "07-28-ceo-finance-fallback",
|
||||
band: item.band,
|
||||
before: item.before,
|
||||
@@ -298,6 +298,7 @@ module.exports = {
|
||||
TARGET_BY_BAND,
|
||||
assertPeopleBaseline,
|
||||
buildRulePlan,
|
||||
execute,
|
||||
getBand,
|
||||
parseArgs,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const {
|
||||
assertPeopleBaseline,
|
||||
buildRulePlan,
|
||||
execute,
|
||||
parseArgs,
|
||||
} = require("../../../src/scripts/apply-ceo-finance-fallback");
|
||||
|
||||
@@ -100,4 +101,83 @@ describe("CEO finance fallback production apply contract", () => {
|
||||
expect(parseArgs(["--apply", "--format=json"])).toEqual({ apply: true, format: "json" });
|
||||
expect(() => parseArgs(["--force"])).toThrow("Unsupported argument");
|
||||
});
|
||||
|
||||
it("supplies an explicit UUID for each raw audit-log insert", async () => {
|
||||
const ruleIds = [
|
||||
"11111111-1111-4111-8111-111111111111",
|
||||
"22222222-2222-4222-8222-222222222222",
|
||||
"33333333-3333-4333-8333-333333333333",
|
||||
];
|
||||
const sourceRows = currentRows().map((row, index) => ({ ...row, id: ruleIds[index] }));
|
||||
const targetRows = sourceRows.map((row) => ({
|
||||
...row,
|
||||
level2_role: row.id === ruleIds[2] ? "ceo" : "finance",
|
||||
level3_role: row.id === ruleIds[2] ? "finance" : null,
|
||||
owner_self_fallback_role: "finance",
|
||||
}));
|
||||
const adminId = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
|
||||
const auditCalls = [];
|
||||
const transactionCommands = [];
|
||||
let ruleSelectCount = 0;
|
||||
let invariantCount = 0;
|
||||
const client = {
|
||||
query: vi.fn(async (sql, params = []) => {
|
||||
const normalized = String(sql).replace(/\s+/g, " ").trim();
|
||||
if (normalized.startsWith("BEGIN ") || normalized.startsWith("ROLLBACK")) {
|
||||
transactionCommands.push(normalized);
|
||||
return {};
|
||||
}
|
||||
if (normalized.includes("FROM approval_rules")) {
|
||||
ruleSelectCount += 1;
|
||||
return { rows: ruleSelectCount === 1 ? sourceRows : targetRows };
|
||||
}
|
||||
if (normalized.includes("JOIN employee_roles selected_role")) {
|
||||
if (params[0] === "ceo") {
|
||||
return { rows: [{ id: "ceo-id", direct_manager_id: null, has_wecom_binding: true, roles: ["ceo"] }] };
|
||||
}
|
||||
if (params[0] === "finance") {
|
||||
return { rows: [{ id: "finance-id", direct_manager_id: null, has_wecom_binding: true, roles: ["finance"] }] };
|
||||
}
|
||||
return { rows: [{ id: adminId, direct_manager_id: null, has_wecom_binding: false, roles: ["admin"] }] };
|
||||
}
|
||||
if (normalized.includes("AS active_employees")) {
|
||||
invariantCount += 1;
|
||||
return { rows: [{ active_employees: 6, active_role_rows: 8, active_bindings: 6, workflow_snapshots: 0 }] };
|
||||
}
|
||||
if (normalized.startsWith("UPDATE approval_rules")) return { rowCount: 1, rows: [{ id: params[0] }] };
|
||||
if (normalized.startsWith("INSERT INTO audit_logs")) {
|
||||
auditCalls.push({ sql: normalized, params });
|
||||
return { rowCount: 1 };
|
||||
}
|
||||
throw new Error(`unexpected query: ${normalized}`);
|
||||
}),
|
||||
release: vi.fn(),
|
||||
};
|
||||
const pool = { connect: vi.fn(async () => client), end: vi.fn(async () => {}) };
|
||||
|
||||
await expect(execute({ apply: false, format: "json" }, pool)).resolves.toMatchObject({
|
||||
status: "DRY_RUN_PASS",
|
||||
rules: 3,
|
||||
auditRows: 0,
|
||||
});
|
||||
expect(invariantCount).toBe(2);
|
||||
expect(transactionCommands).toEqual([
|
||||
"BEGIN ISOLATION LEVEL SERIALIZABLE",
|
||||
"ROLLBACK",
|
||||
]);
|
||||
expect(auditCalls).toHaveLength(3);
|
||||
for (const [index, call] of auditCalls.entries()) {
|
||||
expect(call.sql).toContain("(id, request_id, actor_id");
|
||||
expect(call.sql).toContain("VALUES ($1::uuid, $2, $3::uuid");
|
||||
expect(call.params[0]).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
|
||||
expect(call.params[1]).toMatch(/^ceo-finance-fallback-[0-9a-f-]+$/i);
|
||||
expect(call.params[2]).toBe(adminId);
|
||||
expect(call.params[3]).toBe(ruleIds[index]);
|
||||
expect(JSON.parse(call.params[4])).toMatchObject({
|
||||
task: "07-28-ceo-finance-fallback",
|
||||
band: ["small", "medium", "large"][index],
|
||||
});
|
||||
expect(call.params).toHaveLength(5);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户