Skip to content
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
3626eaa
default medusa policies
carlos-r-l-rodrigues Jan 14, 2026
3f1bb59
rm non used import
carlos-r-l-rodrigues Jan 14, 2026
87ab7ec
check ff to wrap
carlos-r-l-rodrigues Jan 14, 2026
f206dce
types
carlos-r-l-rodrigues Jan 15, 2026
3d825b5
Merge branch 'develop' into chore/apply-middleware-policies
carlos-r-l-rodrigues Jan 15, 2026
73e06a0
wip
carlos-r-l-rodrigues Jan 15, 2026
806c7ea
post endpoints
carlos-r-l-rodrigues Jan 15, 2026
8112f8c
Merge branch 'develop' into chore/apply-middleware-policies
carlos-r-l-rodrigues Jan 15, 2026
658fd93
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 15, 2026
df414a7
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 15, 2026
c45d80d
POST policies
carlos-r-l-rodrigues Jan 16, 2026
1c60ebb
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 16, 2026
f7c1368
remove method all
carlos-r-l-rodrigues Jan 18, 2026
1521c6f
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 18, 2026
9fe4b98
create policy
carlos-r-l-rodrigues Jan 19, 2026
54afd6f
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 19, 2026
887bb46
missing entity
carlos-r-l-rodrigues Jan 19, 2026
89cc7f0
Merge branch 'chore/apply-middleware-policies' of https://github.com/…
carlos-r-l-rodrigues Jan 19, 2026
951c33d
field alias parse
carlos-r-l-rodrigues Jan 20, 2026
7fb1a48
wrap middleware with policies only
carlos-r-l-rodrigues Jan 20, 2026
62c0e7e
rm log
carlos-r-l-rodrigues Jan 20, 2026
845f9f1
tests
carlos-r-l-rodrigues Jan 20, 2026
48de7d3
rm from rbac
carlos-r-l-rodrigues Jan 20, 2026
72890fe
Merge branch 'develop' into chore/apply-middleware-policies
carlos-r-l-rodrigues Jan 21, 2026
497ff7c
Merge branch 'chore/apply-middleware-policies' into feat/filter-query…
carlos-r-l-rodrigues Jan 21, 2026
6a128dc
update missing policies
carlos-r-l-rodrigues Jan 21, 2026
13afa19
Merge branch 'chore/apply-middleware-policies' into feat/filter-query…
carlos-r-l-rodrigues Jan 21, 2026
eda0ee7
rm policy
carlos-r-l-rodrigues Jan 21, 2026
bc44469
rm duplicate
carlos-r-l-rodrigues Jan 21, 2026
56e17db
Merge branch 'chore/apply-middleware-policies' into feat/filter-query…
carlos-r-l-rodrigues Jan 21, 2026
94a2ae0
Merge branch 'develop' into chore/apply-middleware-policies
carlos-r-l-rodrigues Jan 22, 2026
a6fa291
Merge branch 'chore/apply-middleware-policies' into feat/filter-query…
carlos-r-l-rodrigues Jan 22, 2026
4f44160
Merge branch 'develop' into chore/apply-middleware-policies
carlos-r-l-rodrigues Jan 22, 2026
2cc50b6
Merge branch 'chore/apply-middleware-policies' into feat/filter-query…
carlos-r-l-rodrigues Jan 22, 2026
3b31002
Merge branch 'develop' of https://github.com/medusajs/medusa into fea…
carlos-r-l-rodrigues Jan 22, 2026
780bf31
* resources
carlos-r-l-rodrigues Jan 22, 2026
186026e
rm policis from rbac
carlos-r-l-rodrigues Jan 22, 2026
f14fe3a
chore(): cleanup and improvements
adrien2p Jan 23, 2026
dc014ab
Merge branch 'develop' into feat/filter-query-fields
carlos-r-l-rodrigues Jan 23, 2026
9e11451
new feature flag and better test expectations
carlos-r-l-rodrigues Jan 23, 2026
6e8dd7c
cart route
carlos-r-l-rodrigues Jan 23, 2026
4576745
Merge branch 'develop' into feat/filter-query-fields
carlos-r-l-rodrigues Jan 23, 2026
51b295a
!entity
carlos-r-l-rodrigues Jan 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe("Middleware file loader", () => {
},
]
`)

expect(loader.getMiddlewares()).toMatchInlineSnapshot(`
[
{
Expand Down
307 changes: 1 addition & 306 deletions packages/core/framework/src/http/__tests__/validate-query.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { z } from "@medusajs/deps/zod"
import { MedusaError } from "@medusajs/utils"
import { validateAndTransformQuery } from "../utils/validate-query"
import { MedusaNextFunction, MedusaRequest, MedusaResponse } from "../types"
import { RestrictedFields } from "../utils/restricted-fields"
import { QueryConfig } from "@medusajs/types"
import { validateAndTransformQuery } from "../utils/validate-query"

export const createSelectParams = () => {
return z.object({
Expand Down Expand Up @@ -453,307 +451,4 @@ describe("validateAndTransformQuery", () => {
})
)
})

it("should throw when attempting to transform the input if disallowed fields are requested", async () => {
let mockRequest = {
restrictedFields: new RestrictedFields(),
query: {
fields: "+test_prop",
},
} as unknown as MedusaRequest
const mockResponse = {} as MedusaResponse
const nextFunction: MedusaNextFunction = jest.fn()

let queryConfig: any = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
isList: true,
}

let middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [test_prop] are not valid`
)
)

mockRequest = {
...mockRequest,
query: {
fields: "product",
},
} as unknown as MedusaRequest

queryConfig = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
isList: true,
}

middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [product] are not valid`
)
)

mockRequest = {
...mockRequest,
query: {
fields: "store",
},
} as unknown as MedusaRequest

queryConfig = {
defaults: [
"id",
"created_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
"product",
"product.variants",
"store.name",
],
isList: true,
}

middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [store] are not valid`
)
)

mockRequest = {
...mockRequest,
query: {
fields: "*product",
},
} as unknown as MedusaRequest

queryConfig = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
isList: true,
}

middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [product] are not valid`
)
)

mockRequest = {
...mockRequest,
query: {
fields: "*product.variants",
},
} as unknown as MedusaRequest

queryConfig = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
"product",
],
isList: true,
}

middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [product.variants] are not valid`
)
)

mockRequest = {
...mockRequest,
query: {
fields: "*product",
},
} as unknown as MedusaRequest

queryConfig = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
allowed: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
"product.title",
],
isList: true,
}

middleware = validateAndTransformQuery(createFindParams(), queryConfig)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [product] are not valid`
)
)
})

it("should throw when attempting to transform the input if restricted fields are requested", async () => {
const restrictedFields = new RestrictedFields()
let mockRequest = {
restrictedFields,
query: {
fields: "*product",
},
} as unknown as MedusaRequest

restrictedFields.add(["product"])

const mockResponse = {} as MedusaResponse
const nextFunction: MedusaNextFunction = jest.fn()

const queryConfig: QueryConfig<any> = {
defaults: [
"id",
"created_at",
"updated_at",
"deleted_at",
"metadata.id",
"metadata.parent.id",
"metadata.children.id",
"metadata.product.id",
],
isList: true,
}

const middleware = validateAndTransformQuery(
createFindParams(),
queryConfig
)

await middleware(mockRequest, mockResponse, nextFunction)

expect(nextFunction).toHaveBeenLastCalledWith(
new MedusaError(
MedusaError.Types.INVALID_DATA,
`Requested fields [metadata.product.id, product] are not valid`
)
)
})
})
13 changes: 10 additions & 3 deletions packages/core/framework/src/http/middleware-file-loader.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from "@medusajs/deps/zod"
import { dynamicImport, FileSystem, isFileSkipped } from "@medusajs/utils"
import { join } from "path"
import { z } from "@medusajs/deps/zod"

import { logger } from "../logger"
import {
Expand Down Expand Up @@ -124,8 +124,15 @@ export class MiddlewareFileLoader {
})
}

if (route.middlewares) {
route.middlewares.forEach((middleware) => {
if (route.middlewares || route.policies) {
const middlewares = route.middlewares ?? []
if (route.policies && !route.middlewares?.length) {
middlewares.push((_, __, next) => {
next()
})
}
Comment on lines +129 to +133
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: any reason for pushing a noop there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we wrap the policy checks and run the original middleware, in this case, there were none.
Potentially I can check on the wrapper if there is any original function to be executed, but I was affraid of breaking something unexpected.
Will run some real tests and if I can have this removed, I'll do it in a next PR.


middlewares.forEach((middleware) => {
result.middleware.push({
handler: middleware,
matcher: matcher,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MedusaError } from "@medusajs/utils"
import { hasPermission } from "../../utils/has-permission"
import { hasPermission } from "../../policies/has-permission"
import type {
AuthenticatedMedusaRequest,
MedusaNextFunction,
Expand Down
Loading