diff --git a/packages/runtime/src/enhancements/policy/handler.ts b/packages/runtime/src/enhancements/policy/handler.ts index cc0ea4f03..997e727d5 100644 --- a/packages/runtime/src/enhancements/policy/handler.ts +++ b/packages/runtime/src/enhancements/policy/handler.ts @@ -41,7 +41,7 @@ type FindOperations = 'findUnique' | 'findUniqueOrThrow' | 'findFirst' | 'findFi // input arg type for `check` API type PermissionCheckArgs = { operation: PolicyCrudKind; - filter?: Record; + where?: Record; }; /** @@ -1466,11 +1466,11 @@ export class PolicyProxyHandler implements Pr return constraint; } - if (args.filter) { + if (args.where) { // combine runtime filters with generated constraints const extraConstraints: CheckerConstraint[] = []; - for (const [field, value] of Object.entries(args.filter)) { + for (const [field, value] of Object.entries(args.where)) { if (value === undefined) { continue; } diff --git a/packages/schema/src/plugins/enhancer/enhance/checker-type-generator.ts b/packages/schema/src/plugins/enhancer/enhance/checker-type-generator.ts index fe6c415cc..7202f2cdf 100644 --- a/packages/schema/src/plugins/enhancer/enhance/checker-type-generator.ts +++ b/packages/schema/src/plugins/enhancer/enhance/checker-type-generator.ts @@ -31,7 +31,7 @@ export interface ModelCheckers { function generateDataModelChecker(dataModel: DataModel) { return `{ - check(args: { operation: PolicyCrudKind, filter?: ${generateDataModelArgs(dataModel)} }): Promise + check(args: { operation: PolicyCrudKind, where?: ${generateDataModelArgs(dataModel)} }): Promise }`; } diff --git a/tests/integration/tests/enhancements/with-policy/checker.test.ts b/tests/integration/tests/enhancements/with-policy/checker.test.ts index 4a2c0193e..e4ca61fad 100644 --- a/tests/integration/tests/enhancements/with-policy/checker.test.ts +++ b/tests/integration/tests/enhancements/with-policy/checker.test.ts @@ -48,7 +48,7 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveFalsy(); }); it('unconditional allow', async () => { @@ -63,7 +63,7 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 0 } })).toResolveTruthy(); }); it('multiple allow rules', async () => { @@ -79,9 +79,9 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 0 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 2 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 0 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 2 } })).toResolveTruthy(); }); it('deny rule', async () => { @@ -97,9 +97,9 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 0 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 2 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 0 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 2 } })).toResolveTruthy(); }); it('int field condition', async () => { @@ -118,21 +118,21 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 0 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 0 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); await expect(db.model.check({ operation: 'create' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { value: 0 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { value: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'create', where: { value: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'create', where: { value: 1 } })).toResolveFalsy(); await expect(db.model.check({ operation: 'update' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { value: 1 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'update', filter: { value: 2 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'update', where: { value: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'update', where: { value: 2 } })).toResolveTruthy(); await expect(db.model.check({ operation: 'delete' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'delete', filter: { value: 0 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'delete', filter: { value: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'delete', filter: { value: 2 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'delete', where: { value: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'delete', where: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'delete', where: { value: 2 } })).toResolveFalsy(); }); it('boolean field toplevel condition', async () => { @@ -148,8 +148,8 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: false } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: true } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: false } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: true } })).toResolveTruthy(); }); it('boolean field condition', async () => { @@ -168,20 +168,20 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: false } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: true } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: false } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: true } })).toResolveTruthy(); await expect(db.model.check({ operation: 'create' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { value: true } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'create', filter: { value: false } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'create', where: { value: true } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'create', where: { value: false } })).toResolveTruthy(); await expect(db.model.check({ operation: 'update' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { value: true } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'update', filter: { value: false } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'update', where: { value: true } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'update', where: { value: false } })).toResolveTruthy(); await expect(db.model.check({ operation: 'delete' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'delete', filter: { value: false } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'delete', filter: { value: true } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'delete', where: { value: false } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'delete', where: { value: true } })).toResolveTruthy(); }); it('string field condition', async () => { @@ -197,8 +197,8 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 'user' } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { value: 'admin' } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 'user' } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { value: 'admin' } })).toResolveTruthy(); }); it('enum', async () => { @@ -263,11 +263,11 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 'user' } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 'admin' } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 'user' } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 'admin' } })).toResolveTruthy(); await expect(db.model.check({ operation: 'update' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { value: 'user' } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { value: 'admin' } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'update', where: { value: 'user' } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'update', where: { value: 'admin' } })).toResolveTruthy(); }); it('relation noop', async () => { @@ -292,7 +292,7 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { foo: { x: 0 } } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { foo: { x: 0 } } })).rejects.toThrow( 'Providing filter for field "foo"' ); }); @@ -319,7 +319,7 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { foo: [{ x: 0 }] } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { foo: [{ x: 0 }] } })).rejects.toThrow( 'Providing filter for field "foo"' ); }); @@ -340,21 +340,21 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { x: 0 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1, y: 0 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1, y: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 0 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { x: 1, y: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { x: 1, y: 1 } })).toResolveFalsy(); await expect(db.model.check({ operation: 'create' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { x: 0 } })).toResolveFalsy(); // numbers are non-negative - await expect(db.model.check({ operation: 'create', filter: { x: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { x: 1, y: 0 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { x: 1, y: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'create', where: { x: 0 } })).toResolveFalsy(); // numbers are non-negative + await expect(db.model.check({ operation: 'create', where: { x: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'create', where: { x: 1, y: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'create', where: { x: 1, y: 1 } })).toResolveFalsy(); await expect(db.model.check({ operation: 'update' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { x: 0 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'update', filter: { y: 0 } })).toResolveFalsy(); // numbers are non-negative - await expect(db.model.check({ operation: 'update', filter: { x: 1, y: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'update', where: { x: 0 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'update', where: { y: 0 } })).toResolveFalsy(); // numbers are non-negative + await expect(db.model.check({ operation: 'update', where: { x: 1, y: 1 } })).toResolveFalsy(); }); it('field condition unsolvable', async () => { @@ -371,10 +371,10 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { x: 0 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1, y: 2 } })).toResolveFalsy(); - await expect(db.model.check({ operation: 'read', filter: { x: 1, y: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 0 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 1 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 1, y: 2 } })).toResolveFalsy(); + await expect(db.model.check({ operation: 'read', where: { x: 1, y: 1 } })).toResolveFalsy(); }); it('simple auth condition', async () => { @@ -435,23 +435,23 @@ describe('Permission checker', () => { await expect(enhance().model.check({ operation: 'read' })).toResolveFalsy(); await expect(enhance({ id: 1 }).model.check({ operation: 'read' })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'read', filter: { ownerId: 1 } })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'read', filter: { ownerId: 2 } })).toResolveFalsy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'read', where: { ownerId: 1 } })).toResolveTruthy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'read', where: { ownerId: 2 } })).toResolveFalsy(); await expect(enhance().model.check({ operation: 'create' })).toResolveFalsy(); await expect(enhance({ id: 1 }).model.check({ operation: 'create' })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'create', filter: { ownerId: 1 } })).toResolveFalsy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'create', filter: { ownerId: 2 } })).toResolveTruthy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'create', where: { ownerId: 1 } })).toResolveFalsy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'create', where: { ownerId: 2 } })).toResolveTruthy(); await expect(enhance().model.check({ operation: 'update' })).toResolveFalsy(); await expect(enhance({ id: 1 }).model.check({ operation: 'update' })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'update', filter: { ownerId: 1 } })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'update', filter: { ownerId: 2 } })).toResolveFalsy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'update', where: { ownerId: 1 } })).toResolveTruthy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'update', where: { ownerId: 2 } })).toResolveFalsy(); await expect(enhance().model.check({ operation: 'delete' })).toResolveFalsy(); await expect(enhance({ id: 1 }).model.check({ operation: 'delete' })).toResolveTruthy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'delete', filter: { ownerId: 1 } })).toResolveFalsy(); - await expect(enhance({ id: 1 }).model.check({ operation: 'delete', filter: { ownerId: 2 } })).toResolveTruthy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'delete', where: { ownerId: 1 } })).toResolveFalsy(); + await expect(enhance({ id: 1 }).model.check({ operation: 'delete', where: { ownerId: 2 } })).toResolveTruthy(); }); it('auth null check', async () => { @@ -527,9 +527,9 @@ describe('Permission checker', () => { const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); await expect(db.model.check({ operation: 'create' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'create', filter: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'create', where: { value: 1 } })).toResolveTruthy(); }); it('compilation', async () => { @@ -553,7 +553,7 @@ describe('Permission checker', () => { const prisma = new PrismaClient(); const db = enhance(prisma); db.model.check({ operation: 'read' }); - db.model.check({ operation: 'read', filter: { value: 1 }}); + db.model.check({ operation: 'read', where: { value: 1 }}); `, }, ], @@ -583,22 +583,22 @@ describe('Permission checker', () => { ); const db = enhance(); - await expect(db.model.check({ operation: 'read', filter: { foo: { x: 1 } } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { foo: { x: 1 } } })).rejects.toThrow( `Providing filter for field "foo" is not supported. Only scalar fields are allowed.` ); - await expect(db.model.check({ operation: 'read', filter: { d: new Date() } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { d: new Date() } })).rejects.toThrow( `Providing filter for field "d" is not supported. Only number, string, and boolean fields are allowed.` ); - await expect(db.model.check({ operation: 'read', filter: { value: null } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { value: null } })).rejects.toThrow( `Using "null" as filter value is not supported yet` ); - await expect(db.model.check({ operation: 'read', filter: { value: {} } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { value: {} } })).rejects.toThrow( 'Invalid value type for field "value". Only number, string or boolean is allowed.' ); - await expect(db.model.check({ operation: 'read', filter: { value: 'abc' } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { value: 'abc' } })).rejects.toThrow( 'Invalid value type for field "value". Expected "number"' ); - await expect(db.model.check({ operation: 'read', filter: { value: -1 } })).rejects.toThrow( + await expect(db.model.check({ operation: 'read', where: { value: -1 } })).rejects.toThrow( 'Invalid value for field "value". Only non-negative integers are allowed.' ); }); @@ -615,7 +615,7 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); }); it('float value ignored', async () => { @@ -630,8 +630,8 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 2 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 2 } })).toResolveTruthy(); }); it('negative value ignored', async () => { @@ -646,7 +646,7 @@ describe('Permission checker', () => { ); const db = enhance(); await expect(db.model.check({ operation: 'read' })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 1 } })).toResolveTruthy(); - await expect(db.model.check({ operation: 'read', filter: { value: 2 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 1 } })).toResolveTruthy(); + await expect(db.model.check({ operation: 'read', where: { value: 2 } })).toResolveTruthy(); }); });