Skip to content

Commit 09ca875

Browse files
authored
test(regression): add regression test for issue #2538 (#2607)
2 parents 40c4594 + fa94d38 commit 09ca875

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { createPolicyTestClient } from '@zenstackhq/testtools';
2+
import { describe, expect, it } from 'vitest';
3+
4+
// https://github.com/zenstackhq/zenstack/issues/2538
5+
describe('Regression for issue #2538', () => {
6+
it('nested collection predicates in access policies generate valid SQL', async () => {
7+
const db = await createPolicyTestClient(
8+
`
9+
model User {
10+
id String @id @default(cuid())
11+
access String @default("USER")
12+
permissions UserPermission[]
13+
@@allow('all', true)
14+
}
15+
16+
model Project {
17+
id String @id @default(cuid())
18+
userPermissions UserPermission[]
19+
repositories Repositories[]
20+
@@allow('all', true)
21+
}
22+
23+
model Role {
24+
id String @id @default(cuid())
25+
rolePermissions RolePermission[]
26+
userPermissions UserPermission[]
27+
@@allow('all', true)
28+
}
29+
30+
model RolePermission {
31+
id String @id @default(cuid())
32+
roleId String
33+
role Role @relation(fields: [roleId], references: [id])
34+
area String
35+
canAddEdit Boolean @default(false)
36+
@@allow('all', true)
37+
}
38+
39+
model UserPermission {
40+
id String @id @default(cuid())
41+
userId String
42+
user User @relation(fields: [userId], references: [id])
43+
projectId String
44+
project Project @relation(fields: [projectId], references: [id])
45+
roleId String
46+
role Role @relation(fields: [roleId], references: [id])
47+
accessType String
48+
@@allow('all', true)
49+
}
50+
51+
model Repositories {
52+
id String @id @default(cuid())
53+
projectId String
54+
project Project @relation(fields: [projectId], references: [id])
55+
56+
@@allow('read', true)
57+
@@allow('create',
58+
project.userPermissions?[user == auth() && accessType == 'SPECIFIC_ROLE' &&
59+
role.rolePermissions?[area == 'TestCaseRepository' && canAddEdit]]
60+
)
61+
@@allow('all', auth().access == 'ADMIN')
62+
}
63+
`,
64+
);
65+
66+
const project = await db.project.create({ data: { id: 'project-1' } });
67+
68+
const roleWithPerm = await db.role.create({ data: { id: 'role-1' } });
69+
await db.rolePermission.create({
70+
data: { roleId: roleWithPerm.id, area: 'TestCaseRepository', canAddEdit: true },
71+
});
72+
73+
const roleNoPerm = await db.role.create({ data: { id: 'role-2' } });
74+
await db.rolePermission.create({
75+
data: { roleId: roleNoPerm.id, area: 'TestCaseRepository', canAddEdit: false },
76+
});
77+
78+
const adminUser = await db.user.create({ data: { id: 'admin', access: 'ADMIN' } });
79+
const authorizedUser = await db.user.create({ data: { id: 'user-ok', access: 'USER' } });
80+
const unauthorizedUser = await db.user.create({ data: { id: 'user-no', access: 'USER' } });
81+
82+
await db.userPermission.create({
83+
data: {
84+
userId: authorizedUser.id,
85+
projectId: project.id,
86+
roleId: roleWithPerm.id,
87+
accessType: 'SPECIFIC_ROLE',
88+
},
89+
});
90+
await db.userPermission.create({
91+
data: {
92+
userId: unauthorizedUser.id,
93+
projectId: project.id,
94+
roleId: roleNoPerm.id,
95+
accessType: 'SPECIFIC_ROLE',
96+
},
97+
});
98+
99+
// admin read: verifies SQL is valid even though nested predicate is compiled alongside @@allow('all',...)
100+
await expect(db.$setAuth(adminUser).repositories.findMany()).resolves.toHaveLength(0);
101+
102+
// admin can create
103+
await expect(db.$setAuth(adminUser).repositories.create({ data: { projectId: project.id } })).toResolveTruthy();
104+
105+
// authorizedUser: SPECIFIC_ROLE + role has canAddEdit=true for the right area
106+
await expect(
107+
db.$setAuth(authorizedUser).repositories.create({ data: { projectId: project.id } }),
108+
).toResolveTruthy();
109+
110+
// unauthorizedUser: SPECIFIC_ROLE but role has canAddEdit=false
111+
await expect(
112+
db.$setAuth(unauthorizedUser).repositories.create({ data: { projectId: project.id } }),
113+
).toBeRejectedByPolicy();
114+
});
115+
});

0 commit comments

Comments
 (0)