The port: the one place an application asks whether a subject can perform an operation on an object. It is also the contract every adapter implements. The words are NIST SP 800-162's: subject, object, operation, and environment.
authorize/4when the call reaches the repo: it answers the decision the seam accepts undermediate:.check/4when a branch needs a yes or no and reaches no repo.scope/4when a query covers a whole type: it answers adynamicthe query carries, which can only narrow, and a decision whose object id isnil.review/5when a reviewer asks who can do what today: onescopeper subject under the reviewer's operation id, withnilids alike.
This module is the top-layer boundary. Everything under Mediate that is
not Mediate.Test belongs to it. It can reach Ecto and NimbleOptions.
It reaches nothing from ecto_sql or postgrex, because the port decides
and does not query.
Summary
Types
Under what conditions the subject asks: the facts only the caller knows,
by name, with now from the configured clock beside them. The port
stamps now, so a decider reads the moment of the request from the
environment rather than from a clock of its own.
What the subject asks about: an object type and an id. A decision over a
whole type, which scope/4 makes, carries nil for the id.
Who asks: a kind and an account id. The kind travels with every decision record. The port refuses a kind it does not know.
A person, software that acts alone, or a person who can change the system.
Functions
Decide for one object: the decision to hand the seam, or why not.
The verdict alone for one object.
The review a reviewer asks: a rule and a decision per subject over an object type.
The rule a row must satisfy and the decision the query carries.
Types
@type environment() :: %{:now => DateTime.t(), optional(atom()) => term()}
Under what conditions the subject asks: the facts only the caller knows,
by name, with now from the configured clock beside them. The port
stamps now, so a decider reads the moment of the request from the
environment rather than from a clock of its own.
@type object() :: {atom(), Mediate.Id.t() | nil}
What the subject asks about: an object type and an id. A decision over a
whole type, which scope/4 makes, carries nil for the id.
@type subject() :: {subject_kind(), Mediate.Id.t()}
Who asks: a kind and an account id. The kind travels with every decision record. The port refuses a kind it does not know.
@type subject_kind() :: :user | :non_person_entity | :privileged
A person, software that acts alone, or a person who can change the system.
Functions
@spec authorize(subject(), atom(), object(), Mediate.Port.options()) :: {:ok, Mediate.Decision.t()} | {:error, Mediate.Error.t()}
Decide for one object: the decision to hand the seam, or why not.
@spec check(subject(), atom(), object(), Mediate.Port.options()) :: boolean()
The verdict alone for one object.
@spec review(subject(), [subject()], atom(), atom(), Mediate.Port.options()) :: Mediate.Port.reviewed()
The review a reviewer asks: a rule and a decision per subject over an object type.
@spec scope(subject(), atom(), atom(), Mediate.Port.options()) :: {Ecto.Query.dynamic_expr(), Mediate.Decision.t()}
The rule a row must satisfy and the decision the query carries.