From d404d8275ad7b440fba4ea6f2893d7718add0042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 6 Aug 2026 02:11:01 +0200 Subject: [PATCH] fix: preserve import job wipe ownership Keep durable actor attribution from deleting record-owned jobs. Align provider and idempotency coverage with fail-closed behavior. --- src/lib/__tests__/idempotency.test.ts | 3 ++- src/lib/ai/__tests__/openai-compatible-provider.test.ts | 5 ++++- src/lib/data-wipe/wipe-plan.ts | 4 ++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/__tests__/idempotency.test.ts b/src/lib/__tests__/idempotency.test.ts index f5cce86e6..eb8d41fae 100644 --- a/src/lib/__tests__/idempotency.test.ts +++ b/src/lib/__tests__/idempotency.test.ts @@ -643,7 +643,8 @@ describe("withIdempotency — record-scoped cells", () => { await run(); - expect(claimed().key).toBe(CLIENT_KEY); + expect(prisma.idempotencyKey.findUnique).not.toHaveBeenCalled(); + expect(prisma.idempotencyKey.create).not.toHaveBeenCalled(); }); it("refuses a client key that carries the separator", async () => { diff --git a/src/lib/ai/__tests__/openai-compatible-provider.test.ts b/src/lib/ai/__tests__/openai-compatible-provider.test.ts index 8c7f204b0..b8b12e814 100644 --- a/src/lib/ai/__tests__/openai-compatible-provider.test.ts +++ b/src/lib/ai/__tests__/openai-compatible-provider.test.ts @@ -25,7 +25,10 @@ vi.mock("@/lib/ai/codex-oauth", () => ({ encryptCodexCreds: vi.fn(), decryptCodexCreds: vi.fn(), })); -vi.mock("@/lib/logging/context", () => ({ annotate: vi.fn() })); +vi.mock("@/lib/logging/context", () => ({ + annotate: vi.fn(), + getEvent: vi.fn(() => undefined), +})); vi.mock("undici", async (importOriginal) => { const actual = await importOriginal(); return { diff --git a/src/lib/data-wipe/wipe-plan.ts b/src/lib/data-wipe/wipe-plan.ts index 811e4b034..b30dbb111 100644 --- a/src/lib/data-wipe/wipe-plan.ts +++ b/src/lib/data-wipe/wipe-plan.ts @@ -417,6 +417,10 @@ export const USER_KEPT_FIELDS: Readonly> = { * {@link resolveWipeDelegate} translates; the route is unaware. */ export const WIPE_OWNER_FIELDS: Readonly> = { + // The record owner owns the import payload. The actor is durable audit + // attribution and must not let deleting a manager erase another record's + // import history. + MedicationIntakeImportJob: ["recordUserId"], // Both sides. Wiping only the grantor side would leave the account still // holding read access to other people's records after it asked for // everything of its own to be deleted.