|
28 | 28 | - [Enforcement Actions](#enforcement-actions)
|
29 | 29 | - [Namespace scoped policy binding](#namespace-scoped-policy-binding)
|
30 | 30 | - [CEL Expression Composition](#cel-expression-composition)
|
| 31 | + - [Use Cases](#use-cases) |
31 | 32 | - [Variables](#variables)
|
32 | 33 | - [Secondary Authz](#secondary-authz)
|
33 | 34 | - [Access to namespace metadata](#access-to-namespace-metadata)
|
@@ -1065,28 +1066,88 @@ Details to consider:
|
1065 | 1066 |
|
1066 | 1067 | #### CEL Expression Composition
|
1067 | 1068 |
|
| 1069 | +##### Use Cases |
| 1070 | + |
| 1071 | +###### Code re-use for complicated expressions |
| 1072 | + |
| 1073 | +A CEL expression may not be computationally expensive, but could still be |
| 1074 | +intricate enough that copy-pasting could prove to be a bad decision later on |
| 1075 | +in time. With the addition of the `messageExpression` field, more copy-pasting |
| 1076 | +is expected as well. If a sufficiently complex expression ended up copy-pasted everywhere, |
| 1077 | +and then needs to be updated somehow, it will need that update in every place |
| 1078 | +it was copy-pasted. A variable, on the other hand, will only need to be updated |
| 1079 | +in one place. |
| 1080 | + |
| 1081 | +###### Reusing/memoizing an expensive computation |
| 1082 | + |
| 1083 | +For a CEL expression that runs in O(n^2) time or worse (or otherwise |
| 1084 | +takes a significant amount of time to execute), it would be nice to only run |
| 1085 | +it when necessary. For instance, if multiple validation expressions used the |
| 1086 | +same expensive expression, that expression could be refactored out into a |
| 1087 | +variable. |
| 1088 | + |
1068 | 1089 | ##### Variables
|
1069 | 1090 |
|
1070 |
| -Each CEL "program" is a single expression. There is no support for vaiable |
| 1091 | +Each CEL "program" is a single expression. There is no support for variable |
1071 | 1092 | assignment. This can result in redundant code to traverse maps/arrays or
|
1072 | 1093 | dereference particular fields.
|
1073 | 1094 |
|
1074 | 1095 | We can support this in much the same way as cel-policy-template `terms`. These
|
1075 | 1096 | can be lazily evaluated while the validation expressions are evaluated
|
1076 |
| -(cel-policy-template does this). The results can also be memoized to avoid |
1077 |
| -repeated evaluations if they are shared across validations. |
| 1097 | +(cel-policy-template does this). |
| 1098 | + |
| 1099 | +A policy can include an additional `variables` section. This is an array |
| 1100 | +containing one or more `name` and `expression` pairs, which can be used/re-used by |
| 1101 | +the policy's validation expressions. These results are memoized on a |
| 1102 | +per-validation basis, so if multiple expressions use the same spec variables, |
| 1103 | +the expression that calculates the variable's value will only run once. |
| 1104 | + |
| 1105 | +The variables can be accessed as members of `variables`, which is an object |
| 1106 | +that is exposed to CEL expressions (both validation expressions as well as |
| 1107 | +other variables). |
| 1108 | + |
| 1109 | +For example: |
1078 | 1110 |
|
1079 | 1111 | ```yaml
|
1080 | 1112 | variables:
|
1081 | 1113 | - name: metadataList
|
1082 | 1114 | expression: "spec.list.map(x, x.metadata)"
|
1083 | 1115 | - name: itemMetadataNames
|
1084 |
| - expression: "metadataList.map(m, m.name)" |
| 1116 | + expression: "variables.metadataList.map(m, m.name)" |
1085 | 1117 | validations:
|
1086 |
| - - expression: "itemMetadataNames.all(name, name.startsWith('xyz-'))" |
1087 |
| - - expression: "itemMetadataNames.exists(name, name == 'required')" |
| 1118 | + - expression: "variables.itemMetadataNames.all(name, name.startsWith('xyz-'))" |
| 1119 | + - expression: "variables.itemMetadataNames.exists(name, name == 'required')" |
1088 | 1120 | ```
|
1089 | 1121 |
|
| 1122 | +Variable names must be valid CEL names. What constitutes a |
| 1123 | +valid CEL name can be found at CEL's [language definition](https://github.com/google/cel-spec/blob/master/doc/langdef.md#syntax) under `IDENT`. |
| 1124 | +This validity is checked at write time. |
| 1125 | + |
| 1126 | +For per-policy runtime cost limit purposes, variables count towards the runtime cost limit |
| 1127 | +once per policy. The cost of each variable is computed when it is first evaluated in an |
| 1128 | +expression, mirroring how the cost limit would be calculated if the variable's |
| 1129 | +expression was embedded verbatim. If the runtime cost limit is exceeded in the |
| 1130 | +process, then evaluation halts. No individual variable or expression will be listed as the |
| 1131 | +cause in the resulting message. Whether or not the request actually fails depends on the failure policy, |
| 1132 | +however. For subsequent uses, inclusion of the variable has zero effect on the runtime |
| 1133 | +cost limit. If the variable evaluates to an array or some other iterable, and some expression |
| 1134 | +iterates on it, that of course contributes to the cost limit, but simply including the variable does |
| 1135 | +not add the underlying expression's cost again. |
| 1136 | + |
| 1137 | +Variables are also subject to the per-expression runtime cost limit. Exceeding the per-expression |
| 1138 | +runtime cost limit is always attributed to the variable, unlike the per-policy limit. |
| 1139 | + |
| 1140 | +Variables can only reference other variables that |
| 1141 | +have been previously defined in the `variables` section, so circular references |
| 1142 | +are not allowed. |
| 1143 | + |
| 1144 | +If an error ocurrs during variable evaluation, then the expression |
| 1145 | +that caused it to be evaluated (since variable are always |
| 1146 | +lazily-evaluated) also finishes with an error. Evaluation for that |
| 1147 | +variable is not attempted again during the same validation; if any other |
| 1148 | +expressions attempt to evaluate a variable that already failed an evaluation |
| 1149 | +attempt, they will also be considered to have failed. |
| 1150 | + |
1090 | 1151 | #### Secondary Authz
|
1091 | 1152 |
|
1092 | 1153 | We have general agreement to include this as a feature, but need to provide
|
|
0 commit comments