actor User { }
resource Organization {
roles = ["admin", "member"];
permissions = [
"read", "add_member", "repository.create",
];
# role hierarchy:
# admins inherit all member permissions
"member" if "admin";
# organization level permissions
"read" if "member";
"add_member" if "admin";
# permission to create a repository
# in the organization
"repository.create" if "admin";
}
resource Repository {
permissions = ["read", "delete"];
roles = ["member", "admin"];
relations = {
organization: Organization,
};
"admin" if "admin" on "organization";
# admins inherit all member permissions
"member" if "admin";
"read" if "member";
"delete" if "admin";
}
# like `role if role on "organization"`
# but with an additional condition `is_protected`
has_role(actor: Actor, role: String, repository: Repository) if
not is_protected(repository) and
org matches Organization and
has_relation(repository, "organization", org) and
has_role(actor, role, org);
test "organization members can only read repositories that are not protected" {
setup {
has_role(User{"alice"}, "member", Organization{"acme"});
has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
has_relation(Repository{"bar"}, "organization", Organization{"acme"});
is_protected(Repository{"bar"});
has_relation(Repository{"foo"}, "organization", Organization{"acme"});
is_protected(Repository{"foo"});
# grant Alice explicit access to foo
has_role(User{"alice"}, "member", Repository{"foo"});
}
assert has_role(User{"alice"}, "member", Repository{"anvil"});
assert allow(User{"alice"}, "read", Repository{"anvil"});
assert_not allow(User{"alice"}, "read", Repository{"bar"});
assert allow(User{"alice"}, "read", Repository{"foo"});
}
test "org admins can unconditionally read and delete repositories" {
setup {
has_role(User{"alice"}, "admin", Organization{"acme"});
has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
is_protected(Repository{"anvil"});
}
assert allow(User{"alice"}, "read", Repository{"anvil"});
assert allow(User{"alice"}, "delete", Repository{"anvil"});
}