Skip to content

Commit 484b920

Browse files
authored
fix: field-level access is incorrectly rejected when there're no allow rules (#1510)
1 parent 9c7527f commit 484b920

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

packages/schema/src/plugins/enhancer/policy/utils.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,23 @@ export function generateEntityCheckerFunction(
403403
statements.push(`if (${compiled}) { return true; }`);
404404
});
405405

406-
// default: deny unless for 'postUpdate'
407-
statements.push(kind === 'postUpdate' ? 'return true;' : 'return false;');
406+
if (kind === 'postUpdate') {
407+
// 'postUpdate' rule defaults to allow
408+
statements.push('return true;');
409+
} else {
410+
if (forField) {
411+
// if there's no allow rule, for field-level rules, by default we allow
412+
if (allows.length === 0) {
413+
statements.push('return true;');
414+
} else {
415+
// if there's any allow rule, we deny unless any allow rule evaluates to true
416+
statements.push(`return false;`);
417+
}
418+
} else {
419+
// for other cases, defaults to deny
420+
statements.push(`return false;`);
421+
}
422+
}
408423

409424
const func = sourceFile.addFunction({
410425
name: `$check_${model.name}${forField ? '$' + forField.name : ''}${fieldOverride ? '$override' : ''}_${kind}`,

tests/integration/tests/enhancements/with-policy/field-level-policy.test.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('Policy: field-level policy', () => {
2727
id Int @id @default(autoincrement())
2828
x Int
2929
y Int @allow('read', x > 0)
30+
z Int @deny('read', x <= 0)
3031
owner User @relation(fields: [ownerId], references: [id])
3132
ownerId Int
3233
@@ -40,92 +41,106 @@ describe('Policy: field-level policy', () => {
4041
const db = enhance();
4142
let r;
4243

43-
// y is unreadable
44+
// y and x are unreadable
4445

4546
r = await db.model.create({
46-
data: { id: 1, x: 0, y: 0, ownerId: 1 },
47+
data: { id: 1, x: 0, y: 0, z: 0, ownerId: 1 },
4748
});
4849
expect(r.x).toEqual(0);
4950
expect(r.y).toBeUndefined();
51+
expect(r.z).toBeUndefined();
5052

5153
r = await db.model.findUnique({ where: { id: 1 } });
5254
expect(r.y).toBeUndefined();
55+
expect(r.z).toBeUndefined();
5356

5457
r = await db.user.findUnique({ where: { id: 1 }, select: { models: true } });
5558
expect(r.models[0].y).toBeUndefined();
59+
expect(r.models[0].z).toBeUndefined();
5660

5761
r = await db.user.findUnique({ where: { id: 1 }, select: { models: { select: { y: true } } } });
5862
expect(r.models[0].y).toBeUndefined();
63+
expect(r.models[0].z).toBeUndefined();
5964

6065
r = await db.user.findUnique({ where: { id: 1 } }).models();
6166
expect(r[0].y).toBeUndefined();
67+
expect(r[0].z).toBeUndefined();
6268

6369
r = await db.user.findUnique({ where: { id: 1 } }).models({ select: { y: true } });
6470
expect(r[0].y).toBeUndefined();
71+
expect(r[0].z).toBeUndefined();
6572

6673
r = await db.model.findUnique({ select: { x: true }, where: { id: 1 } });
6774
expect(r.x).toEqual(0);
6875
expect(r.y).toBeUndefined();
76+
expect(r.z).toBeUndefined();
6977

7078
r = await db.model.findUnique({ select: { y: true }, where: { id: 1 } });
7179
expect(r.x).toBeUndefined();
7280
expect(r.y).toBeUndefined();
81+
expect(r.z).toBeUndefined();
7382

7483
r = await db.model.findUnique({ select: { x: false, y: true }, where: { id: 1 } });
7584
expect(r.x).toBeUndefined();
7685
expect(r.y).toBeUndefined();
86+
expect(r.z).toBeUndefined();
7787

7888
r = await db.model.findUnique({ select: { x: true, y: true }, where: { id: 1 } });
7989
expect(r.x).toEqual(0);
8090
expect(r.y).toBeUndefined();
91+
expect(r.z).toBeUndefined();
8192

8293
r = await db.model.findUnique({ include: { owner: true }, where: { id: 1 } });
8394
expect(r.x).toEqual(0);
8495
expect(r.owner).toBeTruthy();
8596
expect(r.y).toBeUndefined();
97+
expect(r.z).toBeUndefined();
8698

8799
// y is readable
88100

89101
r = await db.model.create({
90-
data: { id: 2, x: 1, y: 0, ownerId: 1 },
102+
data: { id: 2, x: 1, y: 0, z: 0, ownerId: 1 },
91103
});
92-
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0 }));
104+
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
93105

94106
r = await db.model.findUnique({ where: { id: 2 } });
95-
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0 }));
107+
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
96108

97109
r = await db.user.findUnique({ where: { id: 1 }, select: { models: { where: { id: 2 } } } });
98-
expect(r.models[0]).toEqual(expect.objectContaining({ x: 1, y: 0 }));
110+
expect(r.models[0]).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
99111

100112
r = await db.user.findUnique({
101113
where: { id: 1 },
102-
select: { models: { where: { id: 2 }, select: { y: true } } },
114+
select: { models: { where: { id: 2 }, select: { y: true, z: true } } },
103115
});
104-
expect(r.models[0]).toEqual(expect.objectContaining({ y: 0 }));
116+
expect(r.models[0]).toEqual(expect.objectContaining({ y: 0, z: 0 }));
105117

106118
r = await db.user.findUnique({ where: { id: 1 } }).models({ where: { id: 2 } });
107-
expect(r[0]).toEqual(expect.objectContaining({ x: 1, y: 0 }));
119+
expect(r[0]).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
108120

109121
r = await db.user.findUnique({ where: { id: 1 } }).models({ where: { id: 2 }, select: { y: true } });
110122
expect(r[0]).toEqual(expect.objectContaining({ y: 0 }));
111123

112124
r = await db.model.findUnique({ select: { x: true }, where: { id: 2 } });
113125
expect(r.x).toEqual(1);
114126
expect(r.y).toBeUndefined();
127+
expect(r.z).toBeUndefined();
115128

116129
r = await db.model.findUnique({ select: { y: true }, where: { id: 2 } });
117130
expect(r.x).toBeUndefined();
118131
expect(r.y).toEqual(0);
132+
expect(r.z).toBeUndefined();
119133

120-
r = await db.model.findUnique({ select: { x: false, y: true }, where: { id: 2 } });
134+
r = await db.model.findUnique({ select: { x: false, y: true, z: true }, where: { id: 2 } });
121135
expect(r.x).toBeUndefined();
122136
expect(r.y).toEqual(0);
137+
expect(r.z).toEqual(0);
123138

124-
r = await db.model.findUnique({ select: { x: true, y: true }, where: { id: 2 } });
125-
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0 }));
139+
r = await db.model.findUnique({ select: { x: true, y: true, z: true }, where: { id: 2 } });
140+
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
126141

127142
r = await db.model.findUnique({ include: { owner: true }, where: { id: 2 } });
128-
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0 }));
143+
expect(r).toEqual(expect.objectContaining({ x: 1, y: 0, z: 0 }));
129144
expect(r.owner).toBeTruthy();
130145
});
131146

0 commit comments

Comments
 (0)