Skip to content

Commit

Permalink
chore: document escaping, bindings and modifiers (#39)
Browse files Browse the repository at this point in the history
Signed-off-by: Charles-Edouard Brétéché <[email protected]>
  • Loading branch information
eddycharly authored Oct 4, 2023
1 parent a3d7dee commit 5070ea2
Showing 1 changed file with 184 additions and 4 deletions.
188 changes: 184 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,23 +167,203 @@ spec:
#### Projection modifiers
TODO
Assertion tree expressions support modifiers to influence the way projected values are processed.
The `~` modifier applies to arrays and maps, it mean the input array or map elements will be processed individually by descendants.
When the `~` modifier is not used, descendants receive the whole array, not individual elements.

Consider the following input document:

```yaml
foo:
bar:
- 1
- 2
- 3
```

The policy below does not use the `~` modifier and `foo.bar` array is compared against the expected array:

```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: test
spec:
rules:
- name: foo-bar
validate:
assert:
all:
- foo:
# the content of the `bar` field will be compared against `[1, 2, 3]`
bar:
- 1
- 2
- 3
```
With the `~` modifier, we can apply descendants to all elements in the array individually.
The policy below ensures that all elements in the input array are `< 5`:

```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: test
spec:
rules:
- name: foo-bar
validate:
assert:
all:
- foo:
# with the `~` modifier all elements in the `[1, 2, 3]` array are processed individually and passed to descendants
~.bar:
# the expression `(@ < `5`)` is evaluated for every element and the result is expected to be `true`
(@ < `5`): true
```
The `~` modifier supports binding the index of the element being processed to a named binding with the following syntax `~index_name.bar`. When this is used, we can access the element index in descendants with `$index_name`.

When used with a map, the named binding receives the key of the element being processed.

#### Explicit bindings

TODO
Sometimes it can be useful to refer to a parent node in the assertion tree.

This is possible to add an explicit at every node in the tree by appending the `@binding_name` to the key.

Given the input document:

```yaml
Given the input payload below:
```yaml
foo:
bar: 4
bat: 6
```
The following policy will compute a sum and bind the result to the `sum` binding. A descendant can then use `$sum` and use it:

```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: test
spec:
rules:
- name: foo-bar
validate:
assert:
all:
- foo:
# evaluate expression `(bar + bat)` and bind it to `sum`
(bar + bat)@sum:
# get the `$sum` binding and compare it against `10`
($sum): 10
```
All binding are available to descendants, if a descendant creates a binding with a name that already exists the binding will be overriden for descendants only and it doesn't affect the bindings at upper levels in the tree.
In other words, a node in the tree always sees bindings that are definied in the parents and if a name is reused, the first binding with the given name wins when winding up the tree.
As a consequence, the policy below is perfectly valid:
```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: test
spec:
rules:
- name: foo-bar
validate:
assert:
all:
- foo:
(bar + bat)@sum:
($sum + $sum)@sum:
($sum): 20
($sum): 10
```
Note that all context entries are made available to the rule via bindings:
```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: required-s3-tags
spec:
rules:
- name: require-team-tag
match:
any:
- type: aws_s3_bucket
context:
# creates a `expectedTeam` binding automatically
- name: expectedTeam
variable: Kyverno
validate:
message: Bucket `{{ name }}` ({{ address }}) does not have the required Team tag {{ $expectedTeam }}
assert:
all:
- values:
tags:
# use the `$expectedTeam` binding coming from the context
Team: ($expectedTeam)
```
Finally, we can always access the current resource, policy and rule being evaluated using the builtin `$resource`, `$policy` and `$rule` bindings. No protection is made to prevent you from overriding those bindings though.

#### Escaping projection

TODO
It can be necessary to prevent a projection under certain circumstances.
Consider the following document:

```yaml
foo:
(bar): 4
(baz):
- 1
- 2
- 3
```

Here the `(bar)` key conflict with the projection syntax used.
To workaround this issue, you can escape a projection by surrounding it with `/` characters like this:

```yaml
apiVersion: json.kyverno.io/v1alpha1
kind: Policy
metadata:
name: test
spec:
rules:
- name: foo-bar
validate:
assert:
all:
- foo:
/(bar)/: 10
```

In this case, the leading and trailing `/` characters will be erased and the projection won't be applied.

Note that it's still possible to use the `~` modifier or to create a named binding with and escaped projection.

Keys like this are perfectly valid:
- `~index./baz/`
- `/baz/@foo`
- `~index./baz/@foo`

## SDK

This CLI tool contains an initial implementation of an SDK to allow flexible creation of dedicated policy engines.

The [json-engine](./pkg/json-engine/) at the heart of this tool is built by assembling blocks provided by the [engine](./pkg/engine/) SDK.

## Build kyverno-json

To build this tool locally, simply run:
Expand Down

0 comments on commit 5070ea2

Please sign in to comment.