Files & Folders
Relationships between resources (encoded via the relations
keyword in a
resource block) commonly express roles and permissions that cascade down a
hierarchy, such as files nested in folders in a filesystem.
Implement the logic
In this example, repositories contain folders, and folders contain nested folders and files. Roles cascade down the folder hierarchies from parent folder to children. This rule works recursively: a user has a role on a folder if they have that role on the parent folder. And the user has a role on the parent folder if they have a role on the parent folder's parent.
actor User { }resource Repository { roles = ["reader", "maintainer"];}resource Folder { roles = ["reader", "writer"]; relations = { repository: Repository, folder: Folder, }; "reader" if "reader" on "repository"; "writer" if "maintainer" on "repository"; role if role on "folder";}resource File { permissions = ["read", "write"]; roles = ["reader", "writer"]; relations = { folder: Folder, }; role if role on "folder"; "read" if "reader"; "write" if "writer";}
Test it works
Given the repository structure:
acme/anvil-py├── python│ ├── tests│ │ ├── test.py│ │ └── ...│ └── ...├── ...
We represent the relationships between the Anvil repository and its nested
files and folders with has_relation
facts.
And then check that a repository reader can read the test.py
file.
test "folder roles apply to files" { setup { has_role(User{"alice"}, "reader", Repository{"anvil"}); has_relation(Folder{"python"}, "repository", Repository{"anvil"}); has_relation(Folder{"tests"}, "folder", Folder{"python"}); has_relation(File{"test.py"}, "folder", Folder{"tests"}); } assert allow(User{"alice"}, "read", File{"test.py"});}