Skip to content

Clarify how arrows operate over subject relations #219

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2024
Merged
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
80 changes: 59 additions & 21 deletions pages/spicedb/concepts/schema.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Callout } from 'nextra/components'
import { Callout } from 'nextra/components';
import YouTube from 'react-youtube';
import { InlinePlayground } from '@/components/playground'
import { InlinePlayground } from '@/components/playground';

# Schema Language

Expand All @@ -12,7 +12,8 @@ You can experiment with schemas in real-time with the [Playground](https://play.

The following video provides an overview of schema development using the Playground:

<br /><YouTube videoId="AoK0LrkGFDY" />
<br />
<YouTube videoId="AoK0LrkGFDY" />

After studying this page's content, you may want to also read the [Developing a Schema] doc.

Expand All @@ -22,7 +23,6 @@ After studying this page's content, you may want to also read the [Developing a

The top level of a Schema consists of zero or more [Object Type definitions](#object-type-definitions) and [Caveats](./caveats).


```zed
/**
* somecaveat is a caveat defined
Expand All @@ -38,8 +38,9 @@ definition someobjecttype {}
```

<Callout type="info">
Note that the examples are unprefixed.
You'll need to add the prefix from your permissions system if calling `WriteSchema` for a permissions system hosted in Serverless.
Note that the examples are unprefixed. You'll need to add the prefix from your
permissions system if calling `WriteSchema` for a permissions system hosted in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we fix this in a followup when we add the linter?

Serverless.
</Callout>

### Object Type Definitions
Expand Down Expand Up @@ -84,7 +85,8 @@ definition document {
<Callout type="info">
In the above example, the `user` on `reader` does not contain a sub-relation

Occasionally you will see a subject which has a sub-relation such as `usergroup:admins#members` which refers not just to the `usergroup` as a whole, but the set of members which have that relation to the `usergroup`.
Occasionally you will see a subject which has a sub-relation such as `usergroup:admins#members` which refers not just to the `usergroup` as a whole, but the set of members which have that relation to the `usergroup`.

</Callout>

### Subject Relations
Expand All @@ -105,7 +107,8 @@ definition group {
```

<Callout type="info">
Subject Relations are useful in RBAC-style permissions systems to grant "roles" to _sets_ of subjects, such as the members of a team.
Subject Relations are useful in RBAC-style permissions systems to grant
"roles" to _sets_ of subjects, such as the members of a team.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


### Wildcards
Expand Down Expand Up @@ -134,8 +137,8 @@ resource:someresource viewer user:*
Now _any_ user is a `viewer` of the resource.

<Callout type="warning">
Be **very careful** with wildcard support in your schema!
**Only** grant it to read permissions, unless you intend to allow for universal writing.
Be **very careful** with wildcard support in your schema! **Only** grant it to
read permissions, unless you intend to allow for universal writing.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


### Naming Relations
Expand Down Expand Up @@ -218,7 +221,7 @@ permission can_only_read = reader - writer

#### `->` (Arrow)

Arrows allow for "walking" the heirarchy of relations (and permissions) defined for an object, referencing a permission or relation on the _resulting_ object.
Arrows allow for "walking" the heirarchy of relations (and permissions) defined for an **object** of a subject, referencing a permission or relation on the _resulting_ subject's object.

For example, imagine a schema where a document is found under a folder:

Expand Down Expand Up @@ -283,8 +286,38 @@ definition document {
```

<Callout type="info">
It is _recommended_ that the right side of all arrows refer to **permissions**, instead
of relations. This allows for easy nested computation, and is more readable.
It is _recommended_ that the right side of all arrows refer to
**permissions**, instead of relations, as this allows for easy nested
computation, and is more readable.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


##### Subject relations and Arrows

<Callout type="warning">
Arrows operate on the **object** of the subject(s) found on a `relation`. They
*do not* operate on the relation/permission of a subject, *even if the subject
refers to a relation or permission*.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


For example, in:

```
defintion resource {
relation parent: group#member
permission someperm = parent->something
}
```

`parent->something` refers to the `something` permission on the **group**, and `#member` will be ignored for the arrow.

It is recommended to not use arrows over relations that allow for subject relations without noting that
fact via a comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this

<Callout type="info">
Why is this the case? In one word: **performance**. If arrows operated over
the subject's relation or permission, a full LookupSubjects call would be
necessary for the arrow to correctly "walk", which would make these
CheckPermission requests potentially *incredibly* expensive.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


### Naming Permissions
Expand All @@ -301,15 +334,19 @@ Examples:
| `member` | is member of the object |

<Callout type="info">
You'll note that we also used `member` above in the relation example. Defining `member` as a **permission** might be found when you have multiple "ways" a subject can be a member of a resource, thus changing it from a simple relation to a _computed_ set of subjects.
You'll note that we also used `member` above in the relation example. Defining
`member` as a **permission** might be found when you have multiple "ways" a
subject can be a member of a resource, thus changing it from a simple relation
to a _computed_ set of subjects.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


## Comments

### Documentation Comments

<Callout type="info">
It is **highly** recommended to put doc comments on all definitions, relations and permissions.
It is **highly** recommended to put doc comments on all definitions, relations
and permissions.
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


```zed
Expand All @@ -327,7 +364,7 @@ It is **highly** recommended to put doc comments on all definitions, relations a

## Full Example

<InlinePlayground reference="vlduOcwEOmVY"/>
<InlinePlayground reference="vlduOcwEOmVY" />

## Common Patterns

Expand All @@ -340,7 +377,7 @@ Both admins and members are considered to have membership in the group.
A role can be applied to individual users and groups.
All individually applied users as well as members for applied groups will have the `allowed` permission.

<InlinePlayground reference="CNe3PXNuhypm"/>
<InlinePlayground reference="CNe3PXNuhypm" />

### Global admin permissions

Expand All @@ -350,7 +387,7 @@ In lieu of adding a <code>super_admin</code> relation on every object that can b
Super admin users can be applied to <code>platform</code> and a relation to <code>platform</code> on top level objects.
Admin permission on resources is then defined as the direct owner of the resource as well as through a traversal of the object hierarchy to the platform super admin.

<InlinePlayground reference="m1lRfaaYf9XP"/>
<InlinePlayground reference="m1lRfaaYf9XP" />

### Synthetic relations

Expand All @@ -375,15 +412,16 @@ In this example, a folder can have users with read permission.
Additionally, users that can read the parent folder can also read the current folder.
Checking read permission on a folder will recursively consider these relations as the answer is computed.

<InlinePlayground reference="8tE13O7iMM8W"/>
<InlinePlayground reference="8tE13O7iMM8W" />

<Callout type="info">
Note that since `parent->read` calls the same `read` permission, it will form a recursive lookup across the chain of parent folder(s).
Note that since `parent->read` calls the same `read` permission, it will form
a recursive lookup across the chain of parent folder(s).
</Callout>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one sentence per line, need a linter for this


### Recursive permissions across different resource types

If a non-recursive resource is used as the starting point for a recursive lookup, it is
**very important** that the permission name used on the right side of the arrow is the **same** in both the starting resource type and the parent resource type(s):

<InlinePlayground reference="EWVhjM3vGxE6"/>
<InlinePlayground reference="EWVhjM3vGxE6" />
Loading