BIZ8-9 补强付款导出权限回归

这个提交包含在:
2026-05-13 21:05:53 +08:00
父节点 1c9d0dc612
当前提交 202a77207a
共修改 2 个文件,包含 54 行新增和 2 行删除
@@ -1,6 +1,7 @@
const Fastify = require("fastify");
const exportsRoutes = require("../../../src/routes/exports");
const { AppError } = require("../../../src/utils/AppError");
const ACTOR_ID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
@@ -140,7 +141,12 @@ async function buildApp(options = {}) {
request.employee = actor;
const permissionCodes = actor.permissionCodes ?? [];
if (!permissionCodes.includes("*") && !permissionCodes.includes(permissionCode)) {
throw new Error(`unexpected permission check: ${permissionCode}`);
throw new AppError({
code: "PERM_001",
message: "无权限",
statusCode: 403,
details: { permission: permissionCode },
});
}
});
app.decorate("config", {
@@ -177,6 +183,26 @@ async function buildApp(options = {}) {
},
});
app.setErrorHandler((error, request, reply) => {
if (error instanceof AppError) {
return reply.status(error.statusCode).send({
requestId: request.id,
error: {
code: error.code,
message: error.message,
details: error.details ?? {},
},
});
}
return reply.status(500).send({
requestId: request.id,
error: {
code: "SYS_001",
message: error.message,
},
});
});
await app.register(exportsRoutes, { prefix: "/api" });
return {
app,
@@ -306,4 +332,30 @@ describe("ap operations export route", () => {
await app.close();
});
it.each([
["employee", ["expense.view_own"]],
["admin-only", ["system.users"]],
])("rejects ap operations export for %s without finance permissions", async (_roleName, permissionCodes) => {
const { app, auditCreate } = await buildApp({
actor: {
id: ACTOR_ID,
permissionCodes,
},
});
const response = await app.inject({
method: "POST",
url: "/api/exports/ap-operations",
payload: {
format: "csv",
},
});
expect(response.statusCode).toBe(403);
expect(response.json().error.code).toBe("PERM_001");
expect(auditCreate).not.toHaveBeenCalled();
await app.close();
});
});