Skip to content

Commit 0b466bf

Browse files
authored
fix(delegate): update with "connect" is not properly rejected for polymorphic models (#1675)
1 parent e4e9fbf commit 0b466bf

File tree

3 files changed

+149
-1
lines changed

3 files changed

+149
-1
lines changed

packages/sdk/src/model-meta-generator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ function getBackLink(field: DataModelField) {
298298

299299
const relName = getRelationName(field);
300300

301-
const sourceModel = field.$container as DataModel;
301+
// in case of polymorphism, the source model is the base delegate model
302+
const sourceModel = field.$inheritedFrom ?? (field.$container as DataModel);
302303
const targetModel = field.type.reference.ref as DataModel;
303304

304305
for (const otherField of targetModel.fields) {

tests/integration/tests/enhancements/with-delegate/policy-interaction.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,64 @@ describe('Polymorphic Policy Test', () => {
208208
await expect(db.asset.findUnique({ where: { id: vid1.id } })).toResolveNull();
209209
await expect(db.asset.findUnique({ where: { id: vid2.id } })).toResolveTruthy();
210210
});
211+
212+
it('interaction with connect', async () => {
213+
const schema = `
214+
model User {
215+
id Int @id @default(autoincrement())
216+
}
217+
218+
model Asset {
219+
id Int @id @default(autoincrement())
220+
assetType String
221+
comments Comment[]
222+
223+
@@delegate(assetType)
224+
@@allow('all', true)
225+
}
226+
227+
model Post extends Asset {
228+
title String
229+
postType String
230+
@@delegate(postType)
231+
}
232+
233+
model RatedPost extends Post {
234+
rating Int
235+
}
236+
237+
model Comment {
238+
id Int @id @default(autoincrement())
239+
content String
240+
asset Asset? @relation(fields: [assetId], references: [id])
241+
assetId Int?
242+
@@allow('read,create', true)
243+
@@allow('update', auth().id == 1)
244+
}
245+
`;
246+
247+
const { enhance } = await loadSchema(schema);
248+
const db = enhance();
249+
250+
const comment1 = await db.comment.create({
251+
data: { content: 'Comment1' },
252+
});
253+
254+
await expect(
255+
db.ratedPost.create({ data: { title: 'Post1', rating: 5, comments: { connect: { id: comment1.id } } } })
256+
).toBeRejectedByPolicy();
257+
258+
const post1 = await db.ratedPost.create({ data: { title: 'Post1', rating: 5 } });
259+
await expect(
260+
db.post.update({ where: { id: post1.id }, data: { comments: { connect: { id: comment1.id } } } })
261+
).toBeRejectedByPolicy();
262+
await expect(
263+
db.ratedPost.update({ where: { id: post1.id }, data: { comments: { connect: { id: comment1.id } } } })
264+
).toBeRejectedByPolicy();
265+
266+
const user1Db = enhance({ id: 1 });
267+
await expect(
268+
user1Db.ratedPost.update({ where: { id: post1.id }, data: { comments: { connect: { id: comment1.id } } } })
269+
).toResolveTruthy();
270+
});
211271
});
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { loadSchema } from '@zenstackhq/testtools';
2+
describe('issue 1674', () => {
3+
it('regression', async () => {
4+
const { prisma, enhance } = await loadSchema(
5+
`
6+
model User {
7+
id String @id @default(cuid())
8+
email String @unique @email @length(6, 32)
9+
password String @password @omit
10+
posts Post[]
11+
12+
// everybody can signup
13+
@@allow('create', true)
14+
15+
// full access by self
16+
@@allow('all', auth() == this)
17+
}
18+
19+
model Blog {
20+
id String @id @default(cuid())
21+
createdAt DateTime @default(now())
22+
updatedAt DateTime @updatedAt
23+
24+
post Post? @relation(fields: [postId], references: [id], onDelete: Cascade)
25+
postId String?
26+
}
27+
28+
model Post {
29+
id String @id @default(cuid())
30+
createdAt DateTime @default(now())
31+
updatedAt DateTime @updatedAt
32+
title String @length(1, 256)
33+
content String
34+
published Boolean @default(false)
35+
author User @relation(fields: [authorId], references: [id])
36+
authorId String
37+
38+
blogs Blog[]
39+
40+
type String
41+
42+
// allow read for all signin users
43+
@@allow('read', auth() != null && published)
44+
45+
// full access by author
46+
@@allow('all', author == auth())
47+
48+
@@delegate(type)
49+
}
50+
51+
model PostA extends Post {
52+
}
53+
54+
model PostB extends Post {
55+
}
56+
`
57+
);
58+
59+
const user = await prisma.user.create({
60+
data: { email: '[email protected]', password: 'password' },
61+
});
62+
63+
const blog = await prisma.blog.create({
64+
data: {},
65+
});
66+
67+
const db = enhance(user);
68+
await expect(
69+
db.postA.create({
70+
data: {
71+
content: 'content',
72+
title: 'title',
73+
blogs: {
74+
connect: {
75+
id: blog.id,
76+
},
77+
},
78+
author: {
79+
connect: {
80+
id: user.id,
81+
},
82+
},
83+
},
84+
})
85+
).toBeRejectedByPolicy();
86+
});
87+
});

0 commit comments

Comments
 (0)