Skip to content

Commit 08471d5

Browse files
authored
fix: policy compilation error for deeply nested post-update rules (#1382)
1 parent 54c4bd5 commit 08471d5

File tree

5 files changed

+135
-47
lines changed

5 files changed

+135
-47
lines changed

packages/plugins/trpc/tests/projects/t3-trpc-v10/src/server/api/routers/generated/routers/Post.router.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,6 @@ export interface ClientType<AppRouter extends AnyRouter, Context = AppRouter['_d
6161
>;
6262

6363
};
64-
createMany: {
65-
useMutation: <T extends Prisma.PostCreateManyArgs>(
66-
opts?: UseTRPCMutationOptions<
67-
Prisma.PostCreateManyArgs,
68-
TRPCClientErrorLike<AppRouter>,
69-
Prisma.BatchPayload,
70-
Context
71-
>,
72-
) => Omit<
73-
UseTRPCMutationResult<
74-
Prisma.BatchPayload,
75-
TRPCClientErrorLike<AppRouter>,
76-
Prisma.SelectSubset<T, Prisma.PostCreateManyArgs>,
77-
Context
78-
>,
79-
'mutateAsync'
80-
> & {
81-
mutateAsync: <T extends Prisma.PostCreateManyArgs>(
82-
variables: T,
83-
opts?: UseTRPCMutationOptions<T, TRPCClientErrorLike<AppRouter>, Prisma.BatchPayload, Context>,
84-
) => Promise<Prisma.BatchPayload>;
85-
};
86-
};
8764
create: {
8865

8966
useMutation: <T extends Prisma.PostCreateArgs>(opts?: UseTRPCMutationOptions<

packages/plugins/trpc/tests/projects/t3-trpc-v10/src/server/api/routers/generated/routers/User.router.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,6 @@ export interface ClientType<AppRouter extends AnyRouter, Context = AppRouter['_d
6161
>;
6262

6363
};
64-
createMany: {
65-
useMutation: <T extends Prisma.UserCreateManyArgs>(
66-
opts?: UseTRPCMutationOptions<
67-
Prisma.UserCreateManyArgs,
68-
TRPCClientErrorLike<AppRouter>,
69-
Prisma.BatchPayload,
70-
Context
71-
>,
72-
) => Omit<
73-
UseTRPCMutationResult<
74-
Prisma.BatchPayload,
75-
TRPCClientErrorLike<AppRouter>,
76-
Prisma.SelectSubset<T, Prisma.UserCreateManyArgs>,
77-
Context
78-
>,
79-
'mutateAsync'
80-
> & {
81-
mutateAsync: <T extends Prisma.UserCreateManyArgs>(
82-
variables: T,
83-
opts?: UseTRPCMutationOptions<T, TRPCClientErrorLike<AppRouter>, Prisma.BatchPayload, Context>,
84-
) => Promise<Prisma.BatchPayload>;
85-
};
86-
};
8764
create: {
8865

8966
useMutation: <T extends Prisma.UserCreateArgs>(opts?: UseTRPCMutationOptions<

packages/schema/src/plugins/enhancer/policy/expression-writer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,15 @@ export class ExpressionWriter {
463463
}
464464

465465
private isFutureMemberAccess(expr: Expression): expr is MemberAccessExpr {
466-
return isMemberAccessExpr(expr) && isFutureExpr(expr.operand);
466+
if (!isMemberAccessExpr(expr)) {
467+
return false;
468+
}
469+
470+
if (isFutureExpr(expr.operand)) {
471+
return true;
472+
}
473+
474+
return this.isFutureMemberAccess(expr.operand);
467475
}
468476

469477
private requireIdFields(dataModel: DataModel) {

tests/integration/tests/enhancements/with-policy/post-update.test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,71 @@ describe('With Policy: post update', () => {
237237
).toResolveTruthy();
238238
});
239239

240+
it('collection predicate deep-nested post-update', async () => {
241+
const { prisma, enhance } = await loadSchema(
242+
`
243+
model M1 {
244+
id String @id @default(uuid())
245+
value Int
246+
m2 M2?
247+
@@allow('read', true)
248+
@@allow('update', value > 0 && future().m2.m3?[value > 0])
249+
}
250+
251+
model M2 {
252+
id String @id @default(uuid())
253+
m1 M1 @relation(fields: [m1Id], references:[id])
254+
m1Id String @unique
255+
m3 M3[]
256+
@@allow('all', true)
257+
}
258+
259+
model M3 {
260+
id String @id @default(uuid())
261+
value Int
262+
m2 M2 @relation(fields: [m2Id], references:[id])
263+
m2Id String
264+
265+
@@allow('all', true)
266+
}
267+
`
268+
);
269+
270+
const db = enhance();
271+
272+
await prisma.m1.create({
273+
data: {
274+
id: '1',
275+
value: 1,
276+
m2: {
277+
create: { id: '1', m3: { create: [{ id: '1', value: 0 }] } },
278+
},
279+
},
280+
});
281+
282+
await expect(
283+
db.m1.update({
284+
where: { id: '1' },
285+
data: { value: 2 },
286+
})
287+
).toBeRejectedByPolicy();
288+
289+
await prisma.m3.create({
290+
data: {
291+
id: '2',
292+
m2: { connect: { id: '1' } },
293+
value: 1,
294+
},
295+
});
296+
297+
await expect(
298+
db.m1.update({
299+
where: { id: '1' },
300+
data: { value: 2 },
301+
})
302+
).toResolveTruthy();
303+
});
304+
240305
it('nested to-many', async () => {
241306
const { enhance } = await loadSchema(
242307
`
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
3+
describe('issue 1381', () => {
4+
it('regression', async () => {
5+
await loadSchema(
6+
`
7+
enum MemberRole {
8+
owner
9+
admin
10+
}
11+
12+
enum SpaceType {
13+
contractor
14+
public
15+
private
16+
}
17+
18+
model User {
19+
id String @id @default(cuid())
20+
name String?
21+
email String? @unique @lower
22+
password String? @password @omit
23+
memberships Membership[]
24+
}
25+
26+
model Membership {
27+
userId String
28+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
29+
spaceId String
30+
space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade)
31+
role MemberRole @deny("update", auth() == user)
32+
@@id([userId, spaceId])
33+
}
34+
35+
model Space {
36+
id String @id @default(cuid())
37+
name String
38+
type SpaceType @default(private)
39+
memberships Membership[]
40+
options Option[]
41+
}
42+
43+
model Option {
44+
id String @id @default(cuid())
45+
name String?
46+
spaceId String?
47+
space Space? @relation(fields: [spaceId], references: [id], onDelete: SetNull)
48+
49+
@@allow("update",
50+
future().space.type in [contractor, public] &&
51+
future().space.memberships?[space.type in [contractor, public] && auth() == user && role in [owner, admin]]
52+
)
53+
}
54+
`,
55+
{
56+
provider: 'postgresql',
57+
pushDb: false,
58+
}
59+
);
60+
});
61+
});

0 commit comments

Comments
 (0)