Environments (Components v2)

<<../_v2_banner.md>>

Environments provide a way to configure certain choices the framework makes for components in a realm. Component manifests may define environments and assign them to child realms. An environment applies to a component instance's entire realm, unless some sub-realm overrides it (see Propagation).

Properties

Environments let you configure the following behavior of a realm:

Runners

By registering a runner in an environment declaration, you make it available to any component instance which has that environment assigned to it. Components specify which runner they use with a use declaration naming the runner.

Declaring

Define a new environment by adding an environments declaration to a component manifest.

For an environment to be used, you must assign it to a child or collection. See Propagation.

Environments support two modes of extension, REALM or NONE:

  • REALM: The environment inherits its properties from the environment that was assigned to this component (the “parent environment”). Any new properties will be added on top of those inherited from the parent environment. Any properties that overlap with the parent environment will override the parent.
  • NONE: The environment starts empty, with no initial properties.

Propagation

A component instance is assigned an environment in one of two ways:

  • Its child or collection does not have environment set. In this case, it will receive its parent's environment. This is the most common case.
  • Its child or collection sets environment, which refers to one of the environments defined by this component.

The root component is assigned an environment by component manager. This includes a bootstrap resolver, the ELF runner, and default configuration options.

Environments vs. capability routing

The semantics of environments contrast with capability routing. With capability routing, a capability must be explicitly exposed or offered by every component in the path from the provider to the consumer. The explicit nature of capability routing makes it easy to guarantee that components don‘t receive access to capabilities they shouldn’t have, thus maintaining the principle of least privilege.

However, there are some configuration choices that don‘t make sense to configure on a per-component basis. For example, consider runners. Almost every component needs to use a runner, but defining a new runner is not very common -- certainly less common than defining a protocol capability, for instance. Furthermore, access to a runner doesn’t inherently grant a component much privilege, for the component framework mediates access to the runner‘s protocol and the component can’t use that protocol directly. Therefore, runner capabilities are registered in an environment, which makes them available to any component in the realm to which that environment was assigned (unless some sub-realm decides to set a new environment with the runner absent).