Introspection helpers for AshGrant DSL configuration.
This module provides functions to query AshGrant configuration at runtime, including resolvers, scopes, field groups, and policy settings.
Common Functions
| Function | Description |
|---|---|
resolver/1 | Get the permission resolver for a resource |
default_policies/1 | Get the default_policies setting |
default_field_policies/1 | Get the default_field_policies setting |
resource_name/1 | Get the resource name for permission matching |
scopes/1 | Get all scope definitions |
get_scope/2 | Get a specific scope by name |
resolve_scope_filter/3 | Resolve a scope to its read filter expression |
resolve_write_scope_filter/3 | Resolve a scope to its write filter expression |
field_groups/1 | Get all field group definitions |
get_field_group/2 | Get a specific field group by name |
resolve_field_group/2 | Resolve a field group with inheritance |
owner_field/1 | Deprecated. Use explicit scope expressions instead |
Example
iex> AshGrant.Info.default_policies(MyApp.Blog.Post)
true
iex> AshGrant.Info.resolver(MyApp.Blog.Post)
MyApp.PermissionResolver
iex> AshGrant.Info.scopes(MyApp.Blog.Post) |> Enum.map(& &1.name)
[:all, :own, :published]
Summary
Functions
ash_grant DSL entities
List of action names to generate CanPerform calculations for.
Each generates a :can_<action>? boolean calculation (public by default).
List of action names to generate CanPerform calculations for.
Each generates a :can_<action>? boolean calculation (public by default).
Automatically generate Ash field_policies from field_group definitions.
Automatically generate Ash field_policies from field_group definitions.
Automatically generate standard AshGrant policies.
Automatically generate standard AshGrant policies.
Field to match instance permission IDs against. Defaults to :id (primary key).
Field to match instance permission IDs against. Defaults to :id (primary key).
ash_grant DSL options
DEPRECATED: Use explicit scope :own, expr(field == ^actor(:id)) instead.
DEPRECATED: Use explicit scope :own, expr(field == ^actor(:id)) instead.
Module implementing AshGrant.PermissionResolver behaviour,
or a 2-arity function (actor, context) -> permissions.
Module implementing AshGrant.PermissionResolver behaviour,
or a 2-arity function (actor, context) -> permissions.
The resource name used in permission matching.
The resource name used in permission matching.
DEPRECATED: Use inline scope entities instead.
DEPRECATED: Use inline scope entities instead.
Gets the list of action names configured via can_perform_actions.
Checks if AshGrant is configured for a resource.
Gets the default_field_policies setting.
Gets the default_policies setting.
Gets all field group definitions for a resource.
Gets a specific field group by name.
Gets a specific scope by name.
Gets the field to match instance permission IDs against.
Gets the owner field for "own" scope resolution.
Gets all resolve_argument declarations for a resource.
Resolves a field group to its complete field set including inherited fields.
Resolves a scope to its read filter expression.
Resolves a scope's write filter expression.
Gets the permission resolver for a resource.
Gets the resource name for permission matching.
Gets the description for a specific scope.
Gets the scope resolver for a resource.
Gets all scope_through entities for a resource.
Gets all scope definitions for a resource.
Functions
ash_grant DSL entities
@spec ash_grant_can_perform_actions(dsl_or_extended :: module() | map()) :: {:ok, [atom()]} | :error
List of action names to generate CanPerform calculations for.
Each generates a :can_<action>? boolean calculation (public by default).
Example
can_perform_actions [:update, :destroy]Generates :can_update? and :can_destroy? calculations.
List of action names to generate CanPerform calculations for.
Each generates a :can_<action>? boolean calculation (public by default).
Example
can_perform_actions [:update, :destroy]Generates :can_update? and :can_destroy? calculations.
@spec ash_grant_default_field_policies(dsl_or_extended :: module() | map()) :: {:ok, boolean()} | :error
Automatically generate Ash field_policies from field_group definitions.
When true, AshGrant generates field policies that use AshGrant.FieldCheck
to authorize field access based on the 5th part of permission strings.
When false (default), you can manually write field_policies using
AshGrant.field_check/1 (Mode A).
@spec ash_grant_default_field_policies!(dsl_or_extended :: module() | map()) :: boolean() | no_return()
Automatically generate Ash field_policies from field_group definitions.
When true, AshGrant generates field policies that use AshGrant.FieldCheck
to authorize field access based on the 5th part of permission strings.
When false (default), you can manually write field_policies using
AshGrant.field_check/1 (Mode A).
@spec ash_grant_default_policies(dsl_or_extended :: module() | map()) :: {:ok, boolean() | :all | :write | :read} | :error
Automatically generate standard AshGrant policies.
When enabled, AshGrant will automatically add policies to your resource,
eliminating the need to manually define the policies block.
Options:
false- No policies are generated (default, explicit policies required)trueor:all- Generate policies for both read and write actions:read- Only generate policy for read actions (filter_check):write- Only generate policy for write actions (check)
Generated policies:
policies do
policy action_type(:read) do
authorize_if AshGrant.filter_check()
end
policy action_type([:create, :update, :destroy]) do
authorize_if AshGrant.check()
end
endNote: When using default_policies, you should still add
authorizers: [Ash.Policy.Authorizer] to your resource options.
@spec ash_grant_default_policies!(dsl_or_extended :: module() | map()) :: (boolean() | :all | :write | :read) | no_return()
Automatically generate standard AshGrant policies.
When enabled, AshGrant will automatically add policies to your resource,
eliminating the need to manually define the policies block.
Options:
false- No policies are generated (default, explicit policies required)trueor:all- Generate policies for both read and write actions:read- Only generate policy for read actions (filter_check):write- Only generate policy for write actions (check)
Generated policies:
policies do
policy action_type(:read) do
authorize_if AshGrant.filter_check()
end
policy action_type([:create, :update, :destroy]) do
authorize_if AshGrant.check()
end
endNote: When using default_policies, you should still add
authorizers: [Ash.Policy.Authorizer] to your resource options.
Field to match instance permission IDs against. Defaults to :id (primary key).
When set, instance permissions like "feed:feed_abc:read:" will generate a
filter matching the specified field instead of the primary key.
Example
ash_grant do
instance_key :feed_id
endWith this, "feed:feed_abc:read:" generates WHERE feed_id IN ('feed_abc')
instead of WHERE id IN ('feed_abc').
Field to match instance permission IDs against. Defaults to :id (primary key).
When set, instance permissions like "feed:feed_abc:read:" will generate a
filter matching the specified field instead of the primary key.
Example
ash_grant do
instance_key :feed_id
endWith this, "feed:feed_abc:read:" generates WHERE feed_id IN ('feed_abc')
instead of WHERE id IN ('feed_abc').
ash_grant DSL options
Returns a map containing the and any configured or default values.
DEPRECATED: Use explicit scope :own, expr(field == ^actor(:id)) instead.
The field that identifies the owner of a record. This option is deprecated and will be removed in v1.0.0.
DEPRECATED: Use explicit scope :own, expr(field == ^actor(:id)) instead.
The field that identifies the owner of a record. This option is deprecated and will be removed in v1.0.0.
@spec ash_grant_resolver(dsl_or_extended :: module() | map()) :: {:ok, module() | (any(), any() -> any())} | :error
Module implementing AshGrant.PermissionResolver behaviour,
or a 2-arity function (actor, context) -> permissions.
This resolves permissions for the current actor.
Can be inherited from the domain if the domain uses AshGrant.Domain.
@spec ash_grant_resolver!(dsl_or_extended :: module() | map()) :: (module() | (any(), any() -> any())) | no_return()
Module implementing AshGrant.PermissionResolver behaviour,
or a 2-arity function (actor, context) -> permissions.
This resolves permissions for the current actor.
Can be inherited from the domain if the domain uses AshGrant.Domain.
The resource name used in permission matching.
Defaults to the last part of the module name, lowercased.
For example, MyApp.Blog.Post becomes "post".
The resource name used in permission matching.
Defaults to the last part of the module name, lowercased.
For example, MyApp.Blog.Post becomes "post".
@spec ash_grant_scope_resolver(dsl_or_extended :: module() | map()) :: {:ok, module() | (any(), any() -> any())} | :error
DEPRECATED: Use inline scope entities instead.
Module implementing AshGrant.ScopeResolver behaviour,
or a 2-arity function (scope, context) -> filter.
This resolves scope strings to Ash filter expressions.
If not provided, scopes are resolved from inline scope entities.
@spec ash_grant_scope_resolver!(dsl_or_extended :: module() | map()) :: (module() | (any(), any() -> any())) | no_return()
DEPRECATED: Use inline scope entities instead.
Module implementing AshGrant.ScopeResolver behaviour,
or a 2-arity function (scope, context) -> filter.
This resolves scope strings to Ash filter expressions.
If not provided, scopes are resolved from inline scope entities.
@spec can_perform_actions(Ash.Resource.t()) :: [atom()]
Gets the list of action names configured via can_perform_actions.
Returns an empty list if not configured.
@spec configured?(Ash.Resource.t()) :: boolean()
Checks if AshGrant is configured for a resource.
@spec default_field_policies(Ash.Resource.t()) :: boolean()
Gets the default_field_policies setting.
Returns true if field policies should be auto-generated from field_group definitions,
or false (default) if field policies should be manually defined.
@spec default_policies(Ash.Resource.t()) :: boolean() | :read | :write | :all
Gets the default_policies setting.
Returns false if not configured, or one of:
trueor:all- Generate policies for both read and write:read- Only generate read policy:write- Only generate write policy
@spec field_groups(Ash.Resource.t()) :: [AshGrant.Dsl.FieldGroup.t()]
Gets all field group definitions for a resource.
@spec get_field_group(Ash.Resource.t(), atom()) :: AshGrant.Dsl.FieldGroup.t() | nil
Gets a specific field group by name.
@spec get_scope(Ash.Resource.t(), atom()) :: AshGrant.Dsl.Scope.t() | nil
Gets a specific scope by name.
@spec instance_key(Ash.Resource.t()) :: atom()
Gets the field to match instance permission IDs against.
Defaults to :id (primary key) when not configured.
@spec owner_field(Ash.Resource.t()) :: atom() | nil
Gets the owner field for "own" scope resolution.
DEPRECATED: Use explicit scope :own, expr(field == ^actor(:id)) instead.
This option will be removed in v1.0.0.
@spec resolve_arguments(Ash.Resource.t()) :: [AshGrant.Dsl.ResolveArgument.t()]
Gets all resolve_argument declarations for a resource.
@spec resolve_field_group(Ash.Resource.t(), atom()) :: %{fields: [atom()], masked_fields: map()} | nil
Resolves a field group to its complete field set including inherited fields.
Returns a map with:
:fields- Complete list of accessible field atoms (union of own + inherited):masked_fields- Map of field_name => mask_function for fields masked at THIS level only
Masking is NOT inherited. A higher-level field group sees original values unless it explicitly declares its own masking.
Returns nil if the field group does not exist.
@spec resolve_scope_filter(Ash.Resource.t(), atom(), map()) :: boolean() | Ash.Expr.t()
Resolves a scope to its read filter expression.
Uses the scope's filter field (ignoring any write: option).
If the scope has inheritance, the parent scopes are combined with AND.
Returns false for unknown scopes.
For write action scope resolution, use resolve_write_scope_filter/3 instead.
@spec resolve_write_scope_filter(Ash.Resource.t(), atom(), map()) :: boolean() | Ash.Expr.t()
Resolves a scope's write filter expression.
If the scope has a write field set, uses that value. Otherwise falls back
to the regular filter. This ensures write actions use a direct-field expression
when relationship traversal (exists/dot-paths) cannot be evaluated in-memory.
Returns false for unknown scopes, or when write: false is explicitly set.
Resolution Order
- If scope has
write:set → usewritevalue (false,true, or expression) - If scope has no
write:→ fall back toscope.filter(backward compatible) - Inheritance: parent
write:values are resolved recursively and combined with AND - If any parent returns
false→ short-circuit tofalse(deny propagation)
Examples
# Scope with write: expr(...) → returns the write expression
resolve_write_scope_filter(Resource, :same_org, context)
# => expr(org_id == ^actor(:org_id))
# Scope with write: false → returns false
resolve_write_scope_filter(Resource, :readonly, context)
# => false
# Scope without write: → falls back to filter
resolve_write_scope_filter(Resource, :own, context)
# => expr(author_id == ^actor(:id))
@spec resolver(Ash.Resource.t()) :: module() | function() | nil
Gets the permission resolver for a resource.
@spec resource_name(Ash.Resource.t()) :: String.t()
Gets the resource name for permission matching.
Falls back to deriving from the module name if not configured.
@spec scope_description(Ash.Resource.t(), atom()) :: String.t() | nil
Gets the description for a specific scope.
Returns nil if the scope doesn't exist or has no description.
Examples
iex> AshGrant.Info.scope_description(MyApp.Blog.Post, :own)
"Records owned by the current user"
iex> AshGrant.Info.scope_description(MyApp.Blog.Post, :all)
nil
@spec scope_resolver(Ash.Resource.t()) :: module() | function() | nil
Gets the scope resolver for a resource.
DEPRECATED: Use inline scope entities instead.
@spec scope_throughs(Ash.Resource.t()) :: [AshGrant.Dsl.ScopeThrough.t()]
Gets all scope_through entities for a resource.
Returns an empty list if none are configured.
@spec scopes(Ash.Resource.t()) :: [AshGrant.Dsl.Scope.t()]
Gets all scope definitions for a resource.