zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

[Bug] Access Policy: check() function is being ignored if future() is being used #1642

Closed baenio closed 1 month ago

baenio commented 2 months ago

Description and expected behavior After trying to implement the new check() function in the access control, I found out that when adding the future() function in another policy, it will kinda overwrite the delegated policies. After removing @@allow('update', future().title == 'hello') everything seems to be working normally.

Example

// delegating all operations
model Post {
    id Int @id
    title String
    description String
    author User @relation(fields: [authorId], references: [id])
    authorId Int

    // delegate all access policies to the author:
    @@allow('all', check(author))

    @@allow('update', future().title == 'hello')
}

// imagine I have update permission in the author relation of a post.
// the following db query will fail
const updatedPost = db.post.update({
  where: {id: 'some_id'},
  data: {description: 'new_description'},
});

Environment (please complete the following information):

ymc9 commented 1 month ago

Many thanks for reporting this @baenio ! It's a tricky one. ZenStack internally has a "post-update" policy kind for rules involving future(). If there's no future() call, "post-update" check always passes.

The check(author) call delegates all policy checks (including "post-update" to author), and since User doesn't have any future() rule, "post-update" always passes.

I agree this is very unintuitive. I'm making a fix to stop delegating "post-update" through check() calls.

ymc9 commented 1 month ago

Fixed in 2.5.0