openmct/platform/policy/README.md

93 lines
4.4 KiB
Markdown

# Overview
This bundle provides support for policy in Open MCT. Policy can be
used to limit the applicability of certain actions, or more broadly,
to provide an extension point for arbitrary decisions.
# Services
This bundle introduces the `policyService`, which may be consulted for
various decisions which are intended to be open for extension.
The `policyService` has a single method, `allow`, which takes three
arguments and returns a boolean value (true if policy says this decision
should be allowed, false if not):
* `category`: A string identifying which kind of decision is being made.
Typically, this will be a non-plural form of an extension type that is
being filtered down; for instance, to check whether or not a given
action should be returned by an `actionService`, one would use the
`action` category of extension.
* `candidate`: An object representing the thing which shall or shall not
be allowed. Usually, this will be an instance of an extension of the
category defined above.
* This does need to be the case; additional
policies which are not specific to any extension may also be defined
and consulted using unique `category` identifiers. In this case, the
type of the object delivered for the candidate may be unique to the
policy type.
* `context`: An object representing the context in which the decision is
occurring. Its contents are specific to each policy category.
* `callback`: Optional; a function to call if the policy decision is
rejected. This function will be called with the `message` string
(which may be undefined) of whichever individual policy caused the
operation to fail.
_Design rationale_: Returning a boolean here limits the amount of
information that can be conveyed by a policy decision, but has the
benefit of simplicity. In MCT on the desktop, the policy service
returned a more complex object with both a boolean status and a string
message; the string message was used rarely (by only around 15% of
policy user code) and as such is made optional in the call itself here.
_Design rationale_: Returning a boolean instead of a promise here implies
that policy decisions must occur synchronously. This limits the logic
which can be involved in a policy decision, but broadens its applicability;
policy is meant to be used by a variety of other services to separate out
a certain category of business logic, and a synchronous response means
that this capability may be utilized by both synchronous and asynchronous
services. Additionally, policies will often be used in loops (e.g. to filter
down a set of applicable actions) where latency will have the result of
harming the user experience (e.g. the user right-clicks and gets stuck
waiting for a bunch of policy decisions to complete before a menu showing
available actions can appear.)
The `policyService` is a composite service; it may be modified by adding
decorators, aggregators, etc.
## Service Components
The policy service is most often used by decorators for other composite
services. For instance, this bundle contains a decorator for `actionService`
which filters down the applicable actions exposed by that service based
on policy.
# Policy Categories
This bundle introduces `action` as a policy category. Policies of this
category shall take action instances as their candidate argument, and
action contexts as their context argument.
# Extensions
This bundle introduces the `policies` category of extension. An extension
of this category should have both an implementation, as well as the following
metadata:
* `category`: A string identifying which kind of policy decision this
effects.
* `message`: Optional; a human-readable string describing the policy
decision when it fails.
An extension of this category must also have an implementation which
takes no arguments to its constructor and provides a single method,
`allow`, which takes two arguments, `candidate` and `context` (see
descriptions above under documentation for `actionService`) and returns
a boolean indicating whether or not it allows the policy decision.
Policy decisions require consensus among all policies; that is, if a
single policy returns false, then the policy decision as a whole returns
false. As a consequence, policies should be written in a permissive
manner; that is, they should be designed to prohibit behavior under a
specific set of conditions (by returning false), and allow any behavior
which does not match those conditions (by returning true.)