Ectomancer.FieldAuth (Ectomancer v3.0.3)

Copy Markdown View Source

Field-level authorization for Ectomancer tools.

Allows filtering record fields based on actor permissions after a tool executes. Field auth is applied as a response transform — the row data itself is unaffected, only the returned fields are filtered. The one query-level effect: :list ordering (order_by) is restricted to fields the actor is allowed to see, so a denied field cannot control row order and leak relative values through the ordering.

Usage

expose MyApp.Accounts.User,
  field_authorize: fn actor, field ->
    case field do
      :password_hash -> actor.role == :admin
      :salary -> actor.role == :admin
      :email -> true
      _ -> actor != nil
    end
  end

The callback receives the actor and the field name (as an atom) and should return true (allow) or false (deny).

Summary

Functions

Returns whether field is allowed for actor under the authorization callback. Mirrors the truthiness used by filter_fields/3.

Filters fields from a tool result based on an authorization callback.

Functions

field_allowed?(actor, field, auth_fn)

@spec field_allowed?(any(), atom(), function() | nil) :: boolean()

Returns whether field is allowed for actor under the authorization callback. Mirrors the truthiness used by filter_fields/3.

Used to restrict order_by to fields the actor may actually see, so a denied field cannot control row ordering.

filter_fields(data, actor, auth_fn)

@spec filter_fields(any(), any(), function()) :: any()

Filters fields from a tool result based on an authorization callback.

Works with single structs, lists of structs, and plain maps.

Examples

iex> filter_fields(%User{email: "a@b.com", password_hash: "secret"}, %{role: :admin}, fn _, _ -> true end)
%{email: "a@b.com", password_hash: "secret"}

iex> filter_fields(%User{email: "a@b.com", password_hash: "secret"}, %{role: :user}, fn
...>   _actor, :password_hash -> false
...>   _actor, _ -> true
...> end)
%{email: "a@b.com"}