Add Role resource policies (defense-in-depth)

- PermissionSets: Role read :all for own_data, read_only, normal_user; admin keeps full CRUD
- Role resource: authorizers and policies with HasPermission
- Tests: role_policies_test.exs (read all, create/update/destroy admin only)
- Fix existing tests to pass actor or authorize?: false for Role operations
This commit is contained in:
Moritz 2026-02-04 12:37:48 +01:00
parent 10f37a1246
commit 4d3a64c177
Signed by: moritz
GPG key ID: 1020A035E5DD0824
8 changed files with 304 additions and 51 deletions

View file

@ -12,27 +12,29 @@ defmodule Mv.Authorization.RoleTest do
end
describe "permission_set_name validation" do
test "accepts valid permission set names" do
test "accepts valid permission set names", %{actor: actor} do
attrs = %{
name: "Test Role",
permission_set_name: "own_data"
}
assert {:ok, role} = Authorization.create_role(attrs)
assert {:ok, role} = Authorization.create_role(attrs, actor: actor)
assert role.permission_set_name == "own_data"
end
test "rejects invalid permission set names" do
test "rejects invalid permission set names", %{actor: actor} do
attrs = %{
name: "Test Role",
permission_set_name: "invalid_set"
}
assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.create_role(attrs)
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Authorization.create_role(attrs, actor: actor)
assert error_message(errors, :permission_set_name) =~ "must be one of"
end
test "accepts all four valid permission sets" do
test "accepts all four valid permission sets", %{actor: actor} do
valid_sets = ["own_data", "read_only", "normal_user", "admin"]
for permission_set <- valid_sets do
@ -41,7 +43,7 @@ defmodule Mv.Authorization.RoleTest do
permission_set_name: permission_set
}
assert {:ok, _role} = Authorization.create_role(attrs)
assert {:ok, _role} = Authorization.create_role(attrs, actor: actor)
end
end
end
@ -60,34 +62,36 @@ defmodule Mv.Authorization.RoleTest do
{:ok, system_role} = Ash.create(changeset, actor: actor)
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Authorization.destroy_role(system_role)
Authorization.destroy_role(system_role, actor: actor)
message = error_message(errors, :is_system_role)
assert message =~ "Cannot delete system role"
end
test "allows deletion of non-system roles" do
test "allows deletion of non-system roles", %{actor: actor} do
# is_system_role defaults to false, so regular create works
{:ok, regular_role} =
Authorization.create_role(%{
name: "Regular Role",
permission_set_name: "read_only"
})
Authorization.create_role(
%{name: "Regular Role", permission_set_name: "read_only"},
actor: actor
)
assert :ok = Authorization.destroy_role(regular_role)
assert :ok = Authorization.destroy_role(regular_role, actor: actor)
end
end
describe "name uniqueness" do
test "enforces unique role names" do
test "enforces unique role names", %{actor: actor} do
attrs = %{
name: "Unique Role",
permission_set_name: "own_data"
}
assert {:ok, _} = Authorization.create_role(attrs)
assert {:ok, _} = Authorization.create_role(attrs, actor: actor)
assert {:error, %Ash.Error.Invalid{errors: errors}} =
Authorization.create_role(attrs, actor: actor)
assert {:error, %Ash.Error.Invalid{errors: errors}} = Authorization.create_role(attrs)
assert error_message(errors, :name) =~ "has already been taken"
end
end