actor User { }
resource Role { }
resource Organization {
roles = ["admin", "member"];
permissions = [
"read", "add_member", "repository.create",
"repository.read", "repository.delete"
];
# role hierarchy:
# admins inherit all permissions that members have
"member" if "admin";
# org-level permissions
"read" if "member";
"add_member" if "admin";
# permission to create a repository in the organization
"repository.create" if "admin";
}
# A custom role is defined by the permissions it grants
has_permission(actor: Actor, action: String, org: Organization) if
role matches Role and
has_role(actor, role, org) and
grants_permission(role, action);
resource Repository {
permissions = ["read", "delete"];
roles = ["member", "admin"];
relations = {
organization: Organization,
};
# inherit all roles from the organization
role if role on "organization";
# admins inherit all member permissions
"member" if "admin";
"read" if "member";
"delete" if "admin";
"read" if "repository.read" on "organization";
"delete" if "repository.delete" on "organization";
}
test "custom roles grant the permissions they are assigned" {
setup {
# repository admins can create + delete repositories
# but don't have full admin permissions on the organization
grants_permission(Role{"repo-admin"}, "repository.read");
grants_permission(Role{"repo-admin"}, "repository.create");
grants_permission(Role{"repo-admin"}, "repository.delete");
has_role(User{"alice"}, Role{"repo-admin"}, Organization{"acme"});
has_relation(Repository{"anvil"}, "organization", Organization{"acme"});
}
assert allow(User{"alice"}, "repository.create", Organization{"acme"});
assert allow(User{"alice"}, "read", Repository{"anvil"});
assert allow(User{"alice"}, "delete", Repository{"anvil"});
assert_not allow(User{"alice"}, "add_member", Organization{"acme"});
}