From d2e1e9f8c7862fc132164b5ddbf590efd9cce9eb Mon Sep 17 00:00:00 2001 From: Stevche Radevski Date: Wed, 5 Jun 2024 17:40:54 +0200 Subject: [PATCH] fix: Apply strict schema for all body and query parameters (#7624) --- .../__tests__/customer/admin/customer.spec.ts | 25 ++++++++----------- .../sales-channel/admin/sales-channel.spec.ts | 2 +- .../admin/retrieve-promotion.spec.ts | 2 +- .../src/api/admin/fulfillments/validators.ts | 6 +++++ .../api/utils/__tests__/zod-helper.spec.ts | 12 ++++----- packages/medusa/src/api/utils/zod-helper.ts | 8 +++++- 6 files changed, 31 insertions(+), 24 deletions(-) diff --git a/integration-tests/http/__tests__/customer/admin/customer.spec.ts b/integration-tests/http/__tests__/customer/admin/customer.spec.ts index 56f7713de5..0dd5227685 100644 --- a/integration-tests/http/__tests__/customer/admin/customer.spec.ts +++ b/integration-tests/http/__tests__/customer/admin/customer.spec.ts @@ -174,21 +174,16 @@ medusaIntegrationTestRunner({ describe("POST /admin/customers", () => { it("should create a customer", async () => { - const response = await api - .post( - "/admin/customers", - { - first_name: "newf", - last_name: "newl", - email: "new@email.com", - password: "newpassword", - metadata: { foo: "bar" }, - }, - adminHeaders - ) - .catch((err) => { - console.log(err) - }) + const response = await api.post( + "/admin/customers", + { + first_name: "newf", + last_name: "newl", + email: "new@email.com", + metadata: { foo: "bar" }, + }, + adminHeaders + ) expect(response.status).toEqual(200) expect(response.data.customer).toEqual( diff --git a/integration-tests/http/__tests__/sales-channel/admin/sales-channel.spec.ts b/integration-tests/http/__tests__/sales-channel/admin/sales-channel.spec.ts index 5f70bb95b7..c799ac195c 100644 --- a/integration-tests/http/__tests__/sales-channel/admin/sales-channel.spec.ts +++ b/integration-tests/http/__tests__/sales-channel/admin/sales-channel.spec.ts @@ -448,7 +448,7 @@ medusaIntegrationTestRunner({ it("list sales channels from the publishable api key with free text search filter", async () => { const response = await api.get( - `/admin/sales-channels?q=2&publishable_api_key=${pubKey1.id}`, + `/admin/sales-channels?q=2&publishable_key_id=${pubKey1.id}`, adminHeaders ) diff --git a/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts b/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts index fba74d8f16..fef50a8bd1 100644 --- a/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts +++ b/integration-tests/modules/__tests__/promotion/admin/retrieve-promotion.spec.ts @@ -90,7 +90,7 @@ medusaIntegrationTestRunner({ }) const response = await api.get( - `/admin/promotions/${createdPromotion.id}?fields=id,code&expand=`, + `/admin/promotions/${createdPromotion.id}?fields=id,code`, adminHeaders ) diff --git a/packages/medusa/src/api/admin/fulfillments/validators.ts b/packages/medusa/src/api/admin/fulfillments/validators.ts index 764f45f96f..c782389e26 100644 --- a/packages/medusa/src/api/admin/fulfillments/validators.ts +++ b/packages/medusa/src/api/admin/fulfillments/validators.ts @@ -32,6 +32,12 @@ export const AdminCreateFulfillment = z.object({ labels: z.array(AdminCreateFulfillmentLabel), order: z.object({}), order_id: z.string(), + shipping_option_id: z.string().optional(), + data: z.record(z.unknown()).optional().nullable(), + packed_at: z.coerce.date().optional().nullable(), + shipped_at: z.coerce.date().optional().nullable(), + delivered_at: z.coerce.date().optional().nullable(), + canceled_at: z.coerce.date().optional().nullable(), metadata: z.record(z.unknown()).optional().nullable(), }) diff --git a/packages/medusa/src/api/utils/__tests__/zod-helper.spec.ts b/packages/medusa/src/api/utils/__tests__/zod-helper.spec.ts index a6c9b59403..0f177503c8 100644 --- a/packages/medusa/src/api/utils/__tests__/zod-helper.spec.ts +++ b/packages/medusa/src/api/utils/__tests__/zod-helper.spec.ts @@ -112,7 +112,7 @@ describe("zodValidator", () => { expect(errorMessage).toContain("Invalid request: Field 'id' is required") }) - it("should allow for non-strict parsing", async () => { + it("should apply strict by default", async () => { const schema = z.object({ id: z.string(), }) @@ -123,12 +123,12 @@ describe("zodValidator", () => { company: "Stark Industries", } - const validated = await zodValidator(schema, toValidate) + const errorMessage = await zodValidator(schema, toValidate).catch( + (e) => e.message + ) - expect(JSON.stringify(validated)).toBe( - JSON.stringify({ - id: "1", - }) + expect(errorMessage).toBe( + "Invalid request: Unrecognized fields: 'name, company'" ) }) }) diff --git a/packages/medusa/src/api/utils/zod-helper.ts b/packages/medusa/src/api/utils/zod-helper.ts index 2621c7e392..be41e42e04 100644 --- a/packages/medusa/src/api/utils/zod-helper.ts +++ b/packages/medusa/src/api/utils/zod-helper.ts @@ -113,8 +113,14 @@ export async function zodValidator( zodSchema: z.ZodObject | z.ZodEffects, body: T ): Promise { + let strictSchema = zodSchema + // ZodEffects doesn't support setting as strict, for all other schemas we want to enforce strictness. + if ("strict" in zodSchema) { + strictSchema = zodSchema.strict() + } + try { - return await zodSchema.parseAsync(body) + return await strictSchema.parseAsync(body) } catch (err) { if (err instanceof ZodError) { throw new MedusaError(