From 40e75f40660932c2aa37ead6230e3771b4be74d1 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 4 Feb 2026 13:29:41 +0100 Subject: [PATCH] refactor: reduce nesting in HasPermission.strict_check_with_permissions Extract strict_check_filter_scope/4 to satisfy Credo max depth 2. --- lib/mv/authorization/checks/has_permission.ex | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/mv/authorization/checks/has_permission.ex b/lib/mv/authorization/checks/has_permission.ex index 1139c3c..721cee7 100644 --- a/lib/mv/authorization/checks/has_permission.ex +++ b/lib/mv/authorization/checks/has_permission.ex @@ -132,26 +132,10 @@ defmodule Mv.Authorization.Checks.HasPermission do resource_name ) do :authorized -> - # For :all scope, authorize directly {:ok, true} {:filter, filter_expr} -> - # For :own/:linked scope: - # - With a record, evaluate filter against record for strict authorization - # - Without a record (queries/lists), return false - # - # NOTE: Returning false here forces the use of expr-based bypass policies. - # This is necessary because Ash's policy evaluation doesn't reliably call auto_filter - # when strict_check returns :unknown. Instead, resources should use bypass policies - # with expr() directly for filter-based authorization (see User resource). - if record do - evaluate_filter_for_strict_check(filter_expr, actor, record, resource_name) - else - # No record yet (e.g., read/list queries) - deny at strict_check level - # Resources must use expr-based bypass policies for list filtering - # Create: use a dedicated check that does not return a filter (e.g. CustomFieldValueCreateScope) - {:ok, false} - end + strict_check_filter_scope(record, filter_expr, actor, resource_name) false -> {:ok, false} @@ -175,6 +159,15 @@ defmodule Mv.Authorization.Checks.HasPermission do end end + # For :own/:linked scope: with record evaluate filter; without record deny (resources use bypass + expr). + defp strict_check_filter_scope(record, filter_expr, actor, resource_name) do + if record do + evaluate_filter_for_strict_check(filter_expr, actor, record, resource_name) + else + {:ok, false} + end + end + @impl true def auto_filter(actor, authorizer, _opts) do resource = authorizer.resource