The order every %Scope{} policy decides in, so each policy supplies only its
token grant and its rule. project/4 decides actions on a project and
instance/4 actions with no project.
The order keeps refusals from leaking. A caller without the grant hears
{:error, {:insufficient_scope, grant}} before anything about the target. A
caller the rule refuses who has no standing on the project hears
{:error, :no_standing}, before the MFA check, so it learns nothing about the
project, not even that it exists. Only a caller every other check allows
learns {:error, :scheduled_for_deletion}.
allowed? is computed before the call, so it reads only facts already on the
scope and subject. A rule that needs another project's facts loads that
project's scope through Lightning.Scope, outside allowed? and only after
Decision has answered for the subject's own project. :see_credential does
this for a credential's linked projects, and the sandbox rules for a
sandbox's root project.
A :before_target subject asks only about the grant, so true for it is not
permission. Only Lightning.Policies.Permissions.permit/3 passes it, so that
LightningWeb.Plugs.AuthorizeAction can refuse a missing grant before
anything is loaded.
Summary
Types
The refusal of a caller whose token lacks grant, the one grant the
refusing check needed.
Functions
Decides an action with no project, answering allowed? once one of grants
is held.
Decides an action on a project. grants is one token grant or a list, any
one of which is enough; holding none, the answer is
{:error, {:insufficient_scope, grant}} naming the first. A refused caller
with no standing on the project hears {:error, :no_standing}, and
{:error, :scheduled_for_deletion} comes only to a caller every other check
allows.
Types
@type answer() :: boolean() | {:error, insufficient_scope() | :no_standing | :scheduled_for_deletion}
@type insufficient_scope() :: {:insufficient_scope, grant :: String.t()}
The refusal of a caller whose token lacks grant, the one grant the
refusing check needed.
Functions
@spec instance(Lightning.Scope.t(), term(), grants(), boolean()) :: answer()
Decides an action with no project, answering allowed? once one of grants
is held.
@spec project(Lightning.Scope.t(), term(), grants(), boolean()) :: answer()
Decides an action on a project. grants is one token grant or a list, any
one of which is enough; holding none, the answer is
{:error, {:insufficient_scope, grant}} naming the first. A refused caller
with no standing on the project hears {:error, :no_standing}, and
{:error, :scheduled_for_deletion} comes only to a caller every other check
allows.