spicedb icon indicating copy to clipboard operation
spicedb copied to clipboard

Proposal: Support defining static relationship in schema

Open kindy opened this issue 1 year ago • 8 comments

sometimes(like #346), certain resource types are always associated with specific platform instances. Instead of dynamically creating corresponding platform instance relationships for each new resource instance, it is better to define a static relationship in the schema.

In this way, if there is a change of mind later, only the schema needs to be modified, without having to update all the relationships.

This type of static relationship in schema should applicable to both regular resource IDs and *.

definition user { }
definition role {
  relation member: user
}
definition sys {
  relation admin: user
}

definition sys_a/task {
  relation sys: sys
  relation role: role

  // static relation syntax opt-1
  relation static_sys := sys:sys_a | sys:sys_b
  relation static_role := role:admin

  // static relation syntax opt-2
  relation static_sys = sys:sys_a | sys:sys_b
  relation static_role = role:admin

  permission manage = sys->admin + role_admin->member
}


// static relation exp
sys:*
sys:abc
sys:"+-/ x"
sys:abc#relation
sys:'+-/ x'#relation

kindy avatar Apr 16 '23 15:04 kindy

We have a root object in our model, similar to sys, or platform. It would be great to have a clean solution to this general use case.

In an ideal world I'd love both this and #346. For the specific problem of the root level, this proposal might be best as I suspect it would perform better. However, #346 is more flexible and would potentially allow us to remove two levels of depth from our schema, rather than just the 1 a static relationship would afford.

croemmich avatar Apr 21 '23 21:04 croemmich

@croemmich how would #346 help remove another nesting level?

josephschorr avatar Apr 21 '23 21:04 josephschorr

Now that I think about it more carefully... it wouldn't. As such, I lean more favorably towards this solution.

croemmich avatar Apr 21 '23 21:04 croemmich

@josephschorr In a scenario where I have N different definitions with M permissions each, to be able to grant * access for each of those N * M permissions, I'd need to define a root definition and define those N * M relations/permissions there and also make permission formulas in all of those N definitions more complex.

When N and M are getting quite large this approach feels less and less appealing.

From this perspective I see #346 as a cleaner approach.

alekov87 avatar Sep 12 '23 00:09 alekov87

I'd need to define a root definition and define those N * M relations/permissions there and also make permission formulas in all of those N definitions more complex.

Not quite... you could define a static relationship to a parent "universal", such as a pre-defined "platform", and then just hang the subjects off of that:

definition first {
  relation platform: 'someplatform'
  permission one = platform->admin
  permission two = platform->admin
}

definition second {
  relation platform: 'someplatform'
  permission one = platform->admin
  permission two = platform->admin
}

Resource wildcards have a number of major performance and API implications that will almost certainly mean they are not added

josephschorr avatar Sep 12 '23 15:09 josephschorr

Not quite... you could define a static relationship to a parent "universal", such as a pre-defined "platform", and then just hang the subjects off of that:

How would you go about granting Alice wildcard access to perform action one over any first resource and Bob to perform action one over any second resource? And nothing else.

alekov87 avatar Sep 13 '23 00:09 alekov87

Resource wildcards have a number of major performance and API implications that will almost certainly mean they are not added

Joseph, could you please explain those implications in a bit more detail? I'm really curious to understand it better.

alekov87 avatar Sep 13 '23 00:09 alekov87

How would you go about granting Alice wildcard access to perform action one over any first resource and Bob to perform action one over any second resource? And nothing else.

You'd define a resourcewide type, add Alice to the relation for that associated permission, and then check resourcewide:first-type->whatever_permission. In fact, this would be the recommendation on how to do this today, without any static relationship support

Joseph, could you please explain those implications in a bit more detail? I'm really curious to understand it better.

It has to do with exclusions and lookups. Imagine you have a schema with support for wildcard resources and you define:

definition someresource {
  relation viewer: user
  relation banned: user
  permission view = viewer - banned
}

and then you grant

someresource:*#viewer@user:tom
someresource:specific#banned@user:tom

Now you perform a LookupResources of all resources for which user:tom can view: the returned list of resources needs to be * - {specific} because user:tom has access to all resources except specific. This is a problem we encountered after adding wildcard support to subjects and had to engineer around for LookupSubjects; doing so for LookupResources (and other derivative implementations) would likely become a non-starter, not to mention other performance and design implications

josephschorr avatar Sep 13 '23 12:09 josephschorr