go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/starlark/stdlib/internal/luci/rules/realm.star (about)

     1  # Copyright 2020 The LUCI Authors.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #      http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  """Defines luci.realm(...) rule."""
    16  
    17  load("@stdlib//internal/luci/lib/realms.star", "realms")
    18  load("@stdlib//internal/lucicfg.star", "lucicfg")
    19  load("@stdlib//internal/validate.star", "validate")
    20  
    21  def _realm(
    22          ctx,  # @unused
    23          *,
    24          name,
    25          extends = None,
    26          bindings = None,
    27          enforce_in = None):
    28      """Defines a realm.
    29  
    30      Realm is a named collection of `(<principal>, <permission>)` pairs.
    31  
    32      A LUCI resource can point to exactly one realm by referring to its full
    33      name (`<project>:<realm>`). We say that such resource "belongs to the realm"
    34      or "lives in the realm" or is just "in the realm". We also say that such
    35      resource belongs to the project `<project>`. The corresponding
    36      luci.realm(...) definition then describes who can do what to the resource.
    37  
    38      The logic of how resources get assigned to realms is a part of the public
    39      API of the service that owns resources. Some services may use a static realm
    40      assignment via project configuration files, others may do it dynamically by
    41      accepting a realm when a resource is created via an RPC.
    42  
    43      A realm can "extend" one or more other realms. If a realm `A` extends `B`,
    44      then all permissions defined in `B` are also in `A`. Remembering that a
    45      realm is just a set of `(<principal>, <permission>)` pairs, the "extends"
    46      relation is just a set inclusion.
    47  
    48      There are two special realms that a project can have: "@root" and "@legacy".
    49  
    50      The root realm is implicitly included into all other realms (including
    51      "@legacy"), and it is also used as a fallback when a resource points to a
    52      realm that no longer exists. Without the root realm, such resources become
    53      effectively inaccessible and this may be undesirable. Permissions in the
    54      root realm apply to all realms in the project (current, past and future),
    55      and thus the root realm should contain only administrative-level bindings.
    56      If you are not sure whether you should use the root realm or not, err on
    57      the side of not using it.
    58  
    59      The legacy realm is used for existing resources created before the realms
    60      mechanism was introduced. Such resources usually are not associated with any
    61      realm at all. They are implicitly placed into the legacy realm to allow
    62      reusing realms' machinery for them.
    63  
    64      Note that the details of how resources are placed in the legacy realm are up
    65      to a particular service implementation. Some services may be able to figure
    66      out an appropriate realm for a legacy resource based on resource's existing
    67      attributes. Some services may not have legacy resources at all. The legacy
    68      realm is not used in these case. Refer to the service documentation.
    69  
    70      The primary way of populating the permission set of a realm is via bindings.
    71      Each binding assigns a role to a set of principals (individuals, groups or
    72      LUCI projects). A role is just a set of permissions. A binding grants these
    73      permissions to all principals listed in it.
    74  
    75      Binding can be specific either right here:
    76  
    77          luci.realm(
    78              name = 'try',
    79              bindings = [
    80                  luci.binding(
    81                      roles = 'role/a',
    82                      groups = ['group-a'],
    83                  ),
    84                  luci.binding(
    85                      roles = 'role/b',
    86                      groups = ['group-b'],
    87                  ),
    88              ],
    89          )
    90  
    91      Or separately one by one via luci.binding(...) declarations:
    92  
    93          luci.binding(
    94              realm = 'try',
    95              roles = 'role/a',
    96              groups = ['group-a'],
    97          )
    98          luci.binding(
    99              realm = 'try',
   100              roles = 'role/b',
   101              groups = ['group-b'],
   102          )
   103  
   104      Args:
   105        ctx: the implicit rule context, see lucicfg.rule(...).
   106        name: name of the realm. Must match `[a-z0-9_\\.\\-/]{1,400}` or be
   107          `@root` or `@legacy`. Required.
   108        extends: a reference or a list of references to realms to inherit
   109          permission from. Optional. Default (and implicit) is `@root`.
   110        bindings: a list of luci.binding(...) to add to the realm.
   111        enforce_in: a list of LUCI service IDs that should enforce this realm's
   112          permissions. Children realms inherit and extend this list. Used only
   113          during Realms migration to gradually roll out the enforcement realm by
   114          realm, service by service.
   115      """
   116      return realms.realm(
   117          impl = realms.default_impl,
   118          name = name,
   119          extends = extends,
   120          bindings = bindings,
   121          enforce_in_service = validate.str_list("enforce_in", enforce_in),
   122      )
   123  
   124  realm = lucicfg.rule(impl = _realm)