fix(api): wrap audit log writes inside their parent transactions
Prevents mutations from committing without an audit trail if the auditLog.create call fails after the main write already succeeded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -328,12 +328,13 @@ describe("resource router CRUD", () => {
|
||||
describe("create", () => {
|
||||
it("creates a resource and returns it", async () => {
|
||||
const created = { ...sampleResource, id: "res_new", resourceRoles: [] };
|
||||
const db = {
|
||||
const db: Record<string, unknown> = {
|
||||
resource: {
|
||||
findFirst: vi.fn().mockResolvedValue(null),
|
||||
create: vi.fn().mockResolvedValue(created),
|
||||
},
|
||||
auditLog: { create: vi.fn().mockResolvedValue({}) },
|
||||
$transaction: vi.fn(async (fn: (tx: unknown) => unknown) => fn(db)),
|
||||
};
|
||||
|
||||
const caller = createManagerCaller(db);
|
||||
@@ -399,13 +400,14 @@ describe("resource router CRUD", () => {
|
||||
describe("update", () => {
|
||||
it("updates resource fields", async () => {
|
||||
const updated = { ...sampleResource, displayName: "Alice Updated" };
|
||||
const db = {
|
||||
const db: Record<string, unknown> = {
|
||||
resource: {
|
||||
findUnique: vi.fn().mockResolvedValue(sampleResource),
|
||||
update: vi.fn().mockResolvedValue(updated),
|
||||
},
|
||||
resourceRole: { deleteMany: vi.fn().mockResolvedValue({ count: 0 }) },
|
||||
auditLog: { create: vi.fn().mockResolvedValue({}) },
|
||||
$transaction: vi.fn(async (fn: (tx: unknown) => unknown) => fn(db)),
|
||||
};
|
||||
|
||||
const caller = createManagerCaller(db);
|
||||
@@ -443,11 +445,12 @@ describe("resource router CRUD", () => {
|
||||
describe("deactivate", () => {
|
||||
it("sets isActive to false", async () => {
|
||||
const deactivated = { ...sampleResource, isActive: false };
|
||||
const db = {
|
||||
const db: Record<string, unknown> = {
|
||||
resource: {
|
||||
update: vi.fn().mockResolvedValue(deactivated),
|
||||
},
|
||||
auditLog: { create: vi.fn().mockResolvedValue({}) },
|
||||
$transaction: vi.fn(async (fn: (tx: unknown) => unknown) => fn(db)),
|
||||
};
|
||||
|
||||
const caller = createManagerCaller(db);
|
||||
@@ -469,12 +472,13 @@ describe("resource router CRUD", () => {
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ ...sampleResource, id: "res_1", isActive: false })
|
||||
.mockResolvedValueOnce({ ...sampleResource, id: "res_2", isActive: false });
|
||||
const db = {
|
||||
const auditCreate = vi.fn().mockResolvedValue({});
|
||||
const db: Record<string, unknown> = {
|
||||
resource: {
|
||||
update,
|
||||
},
|
||||
$transaction: vi.fn(async (operations: Promise<unknown>[]) => Promise.all(operations)),
|
||||
auditLog: { create: vi.fn().mockResolvedValue({}) },
|
||||
auditLog: { create: auditCreate },
|
||||
$transaction: vi.fn(async (fn: (tx: unknown) => unknown) => fn(db)),
|
||||
};
|
||||
|
||||
const caller = createManagerCaller(db);
|
||||
@@ -482,7 +486,7 @@ describe("resource router CRUD", () => {
|
||||
|
||||
expect(result).toEqual({ count: 2 });
|
||||
expect(db.$transaction).toHaveBeenCalledTimes(1);
|
||||
expect(db.auditLog.create).toHaveBeenCalledWith(
|
||||
expect(auditCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
entityType: "Resource",
|
||||
|
||||
Reference in New Issue
Block a user