Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
- [ ] Short-circuit pre-create check for scalar-field only policies
- [x] Inject "on conflict do update"
- [x] `check` function
- [ ] Custom functions
- [ ] Accessing tables not in the schema
- [x] Migration
- [ ] Databases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@ export class ExpressionTransformer<Schema extends SchemaDef> {
});

if (currNode) {
invariant(SelectQueryNode.is(currNode), 'expected select query node');
currNode = {
...relation,
selections: [
Expand Down
16 changes: 8 additions & 8 deletions packages/runtime/test/policy/migrated/multi-id-fields.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ describe('Policy tests multiple id fields', () => {
).toResolveTruthy();
});

// TODO: `future()` support
it.skip('multi-id fields id update', async () => {
it('multi-id fields id update', async () => {
const db = await createPolicyTestClient(
`
model A {
Expand All @@ -70,7 +69,8 @@ describe('Policy tests multiple id fields', () => {

@@allow('read', true)
@@allow('create', value > 0)
@@allow('update', value > 0 && future().value > 1)
@@allow('update', value > 0)
@@allow('post-update', value > 1)
}

model B {
Expand Down Expand Up @@ -319,8 +319,7 @@ describe('Policy tests multiple id fields', () => {
expect(await db.c.findUnique({ where: { id: 1 } })).toEqual(expect.objectContaining({ v: 6 }));
});

// TODO: `future()` support
it.skip('multi-id fields nested id update', async () => {
it('multi-id fields nested id update', async () => {
const db = await createPolicyTestClient(
`
model A {
Expand All @@ -333,7 +332,8 @@ describe('Policy tests multiple id fields', () => {

@@allow('read', true)
@@allow('create', value > 0)
@@allow('update', value > 0 && future().value > 1)
@@allow('update', value > 0)
@@allow('post-update', value > 1)
}

model B {
Expand Down Expand Up @@ -369,7 +369,7 @@ describe('Policy tests multiple id fields', () => {
upsert: {
where: { x_y: { x: '2', y: 2 } },
update: { x: '3', y: 3, value: 0 },
create: { x: '4', y: '4', value: 4 },
create: { x: '4', y: 4, value: 4 },
},
},
},
Expand All @@ -384,7 +384,7 @@ describe('Policy tests multiple id fields', () => {
upsert: {
where: { x_y: { x: '2', y: 2 } },
update: { x: '3', y: 3, value: 3 },
create: { x: '4', y: '4', value: 4 },
create: { x: '4', y: 4, value: 4 },
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions packages/runtime/test/policy/migrated/nested-to-one.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ describe('With Policy:nested to-one', () => {
).toBeRejectedNotFound();
});

// TODO: `future()` support
it.skip('nested update id tests', async () => {
it('nested update id tests', async () => {
const db = await createPolicyTestClient(
`
model M1 {
Expand All @@ -216,7 +215,8 @@ describe('With Policy:nested to-one', () => {

@@allow('read', true)
@@allow('create', value > 0)
@@allow('update', value > 1 && future().value > 2)
@@allow('update', value > 1)
@@allow('post-update', value > 2)
}
`,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { describe, expect, it } from 'vitest';
import { createPolicyTestClient } from '../utils';
import { schema } from '../../schemas/petstore/schema';

// TODO: `future()` support
describe.skip('Pet Store Policy Tests', () => {
describe('Pet Store Policy Tests', () => {
it('crud', async () => {
const petData = [
{
Expand Down
3 changes: 1 addition & 2 deletions packages/runtime/test/policy/migrated/todo-sample.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,7 @@ describe('Todo Policy Tests', () => {
expect(r1.lists).toHaveLength(1);
});

// TODO: `future()` support
it.skip('post-update checks', async () => {
it('post-update checks', async () => {
await createSpaceAndUsers(db.$unuseAll());

const user1Db = db.$setAuth({ id: user1.id });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,7 @@ describe('Policy toplevel operations tests', () => {
).toBeTruthy();
});

// TODO: `future()` support
it.skip('update id tests', async () => {
it('update id tests', async () => {
const db = await createPolicyTestClient(
`
model Model {
Expand All @@ -143,7 +142,8 @@ describe('Policy toplevel operations tests', () => {

@@allow('read', value > 1)
@@allow('create', value > 0)
@@allow('update', value > 1 && future().value > 2)
@@allow('update', value > 1)
@@allow('post-update', value > 2)
}
`,
);
Expand All @@ -164,7 +164,7 @@ describe('Policy toplevel operations tests', () => {
value: 1,
},
}),
).toBeRejectedNotFound();
).toBeRejectedByPolicy();

// update success
await expect(
Expand Down
3 changes: 1 addition & 2 deletions packages/runtime/test/policy/todo-sample.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,7 @@ describe('todo sample tests', () => {
expect(r1?.lists).toHaveLength(1);
});

// TODO: `future()` support
it.skip('works with post-update checks', async () => {
it('works with post-update checks', async () => {
const anonDb = await createPolicyTestClient(schema);
await createSpaceAndUsers(anonDb.$unuseAll());

Expand Down
1 change: 1 addition & 0 deletions packages/runtime/test/schemas/petstore/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const schema = {
},
attributes: [
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.field("orderId"), "==", ExpressionUtils._null()), "||", ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("order"), ["user"]), "==", ExpressionUtils.call("auth"))) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("update") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "!=", ExpressionUtils._null()) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("post-update") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("before"), ["name"]), "==", ExpressionUtils.field("name")), "&&", ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("before"), ["category"]), "==", ExpressionUtils.field("category"))), "&&", ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("before"), ["orderId"]), "==", ExpressionUtils._null())) }] }
],
idFields: ["id"],
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime/test/schemas/petstore/schema.zmodel
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ model Pet {
// unsold pets are readable to all; sold ones are readable to buyers only
@@allow('read', orderId == null || order.user == auth())

@@allow('update', auth() != null)

// only allow update to 'orderId' field if it's not set yet (unsold)
@@allow('post-update', before().name == name && before().category == category && before().orderId == null)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/runtime/test/schemas/todo/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export const schema = {
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("read") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.field("ownerId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])), "||", ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("space"), ["members"]), "?", ExpressionUtils.binary(ExpressionUtils.field("userId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]))), "&&", ExpressionUtils.unary("!", ExpressionUtils.field("private")))) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("create") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.field("ownerId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])), "&&", ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("space"), ["members"]), "?", ExpressionUtils.binary(ExpressionUtils.field("userId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])))) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("update") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.field("ownerId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])), "&&", ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("space"), ["members"]), "?", ExpressionUtils.binary(ExpressionUtils.field("userId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])))) }] },
{ name: "@@deny", args: [{ name: "operation", value: ExpressionUtils.literal("post-update") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("before"), ["ownerId"]), "!=", ExpressionUtils.field("ownerId")) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("delete") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.field("ownerId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])) }] }
],
idFields: ["id"],
Expand Down Expand Up @@ -380,7 +381,8 @@ export const schema = {
attributes: [
{ name: "@@deny", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.call("auth"), "==", ExpressionUtils._null()) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("list"), ["ownerId"]), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"])) }] },
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("list"), ["space", "members"]), "?", ExpressionUtils.binary(ExpressionUtils.field("userId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]))), "&&", ExpressionUtils.unary("!", ExpressionUtils.member(ExpressionUtils.field("list"), ["private"]))) }] }
{ name: "@@allow", args: [{ name: "operation", value: ExpressionUtils.literal("all") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.field("list"), ["space", "members"]), "?", ExpressionUtils.binary(ExpressionUtils.field("userId"), "==", ExpressionUtils.member(ExpressionUtils.call("auth"), ["id"]))), "&&", ExpressionUtils.unary("!", ExpressionUtils.member(ExpressionUtils.field("list"), ["private"]))) }] },
{ name: "@@deny", args: [{ name: "operation", value: ExpressionUtils.literal("post-update") }, { name: "condition", value: ExpressionUtils.binary(ExpressionUtils.member(ExpressionUtils.call("before"), ["ownerId"]), "!=", ExpressionUtils.field("ownerId")) }] }
],
idFields: ["id"],
uniqueFields: {
Expand Down
12 changes: 5 additions & 7 deletions packages/runtime/test/schemas/todo/todo.zmodel
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,9 @@ model List {

// when create, owner must be set to current user, and user must be in the space
// update is not allowed to change owner
@@allow('update', ownerId == auth().id && space.members?[userId == auth().id]
// TODO: future() support
// && future().ownerId == ownerId
)
@@allow('update', ownerId == auth().id && space.members?[userId == auth().id])

@@deny('post-update', before().ownerId != ownerId)

// can be deleted by owner
@@allow('delete', ownerId == auth().id)
Expand All @@ -147,7 +146,6 @@ model Todo {
@@allow('all', list.ownerId == auth().id)
@@allow('all', list.space.members?[userId == auth().id] && !list.private)

// TODO: future() support
// // update is not allowed to change owner
// @@deny('update', future().owner != owner)
// update is not allowed to change owner
@@deny('post-update', before().ownerId != ownerId)
}