Skip to content

Commit

Permalink
feat: hold compiled assertion in api
Browse files Browse the repository at this point in the history
Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
  • Loading branch information
eddycharly committed Sep 18, 2024
1 parent f349c31 commit 0e18bed
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 93 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ codegen-deepcopy: $(PACKAGE_SHIM) $(DEEPCOPY_GEN) ## Generate deep copy function
codegen-crds: $(CONTROLLER_GEN) ## Generate CRDs
@echo Generate crds... >&2
@rm -rf $(CRDS_PATH)
@$(CONTROLLER_GEN) paths=./pkg/apis/... crd:crdVersions=v1 output:dir=$(CRDS_PATH)
@$(CONTROLLER_GEN) paths=./pkg/apis/... crd:crdVersions=v1,ignoreUnexportedFields=true output:dir=$(CRDS_PATH)
@echo Copy generated CRDs to embed in the CLI... >&2
@rm -rf pkg/data/crds && mkdir -p pkg/data/crds
@cp $(CRDS_PATH)/* pkg/data/crds
Expand Down
48 changes: 5 additions & 43 deletions pkg/apis/policy/v1alpha1/any.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,27 @@
package v1alpha1

import (
"fmt"

"k8s.io/apimachinery/pkg/util/json"
)

func deepCopy(in any) any {
if in == nil {
return nil
}
switch in := in.(type) {
case string:
return in
case int:
return in
case int32:
return in
case int64:
return in
case float32:
return in
case float64:
return in
case bool:
return in
case []any:
var out []any
for _, in := range in {
out = append(out, deepCopy(in))
}
return out
case map[string]any:
out := map[string]any{}
for k, in := range in {
out[k] = deepCopy(in)
}
return out
}
panic(fmt.Sprintf("deep copy failed - unrecognized type %T", in))
}

// Any can be any type.
// +k8s:deepcopy-gen=false
// +kubebuilder:validation:XPreserveUnknownFields
// +kubebuilder:validation:Type:=""
type Any struct {
// +optional
value any `json:"-"`
_value any
}

func NewAny(value any) Any {
return Any{value}
}

func (t *Any) Value() any {
return t.value
return t._value
}

func (in *Any) DeepCopyInto(out *Any) {
out.value = deepCopy(in.value)
out._value = deepCopy(in._value)
}

func (in *Any) DeepCopy() *Any {
Expand All @@ -72,7 +34,7 @@ func (in *Any) DeepCopy() *Any {
}

func (a *Any) MarshalJSON() ([]byte, error) {
return json.Marshal(a.value)
return json.Marshal(a._value)
}

func (a *Any) UnmarshalJSON(data []byte) error {
Expand All @@ -81,6 +43,6 @@ func (a *Any) UnmarshalJSON(data []byte) error {
if err != nil {
return err
}
a.value = v
a._value = v
return nil
}
39 changes: 0 additions & 39 deletions pkg/apis/policy/v1alpha1/assertion.go
Original file line number Diff line number Diff line change
@@ -1,44 +1,5 @@
package v1alpha1

import (
"k8s.io/apimachinery/pkg/util/json"
)

// +k8s:deepcopy-gen=false
// +kubebuilder:validation:XPreserveUnknownFields
// +kubebuilder:validation:Type:=""
// AssertionTree represents an assertion tree.
type AssertionTree struct {
// +optional
tree any `json:"-"`
}

func NewAssertionTree(value any) AssertionTree {
return AssertionTree{value}
}

func (t *AssertionTree) Raw() any {
return t.tree
}

func (a *AssertionTree) MarshalJSON() ([]byte, error) {
return json.Marshal(a.tree)
}

func (a *AssertionTree) UnmarshalJSON(data []byte) error {
var v any
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
a.tree = v
return nil
}

func (in *AssertionTree) DeepCopyInto(out *AssertionTree) {
out.tree = deepCopy(in.tree)
}

// Assertion contains an assertion tree associated with a message.
type Assertion struct {
// Message is the message associated message.
Expand Down
53 changes: 53 additions & 0 deletions pkg/apis/policy/v1alpha1/assertion_tree.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package v1alpha1

import (
"context"
"sync"

"github.com/kyverno/kyverno-json/pkg/engine/assert"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/validation/field"
)

// +k8s:deepcopy-gen=false
// +kubebuilder:validation:XPreserveUnknownFields
// +kubebuilder:validation:Type:=""
// AssertionTree represents an assertion tree.
type AssertionTree struct {
_tree any
_assertion func() (assert.Assertion, error)
}

func NewAssertionTree(value any) AssertionTree {
return AssertionTree{
_tree: value,
_assertion: sync.OnceValues(func() (assert.Assertion, error) {
return assert.Parse(context.Background(), nil, value)
}),
}
}

func (t *AssertionTree) Assertion(ctx context.Context, path *field.Path) (assert.Assertion, error) {
if t._tree == nil {
return nil, nil
}
return t._assertion()
}

func (a *AssertionTree) MarshalJSON() ([]byte, error) {
return json.Marshal(a._tree)
}

func (a *AssertionTree) UnmarshalJSON(data []byte) error {
var v any
err := json.Unmarshal(data, &v)
if err != nil {
return err
}
a._tree = v
return nil
}

func (in *AssertionTree) DeepCopyInto(out *AssertionTree) {
out._tree = deepCopy(in._tree)
}
40 changes: 40 additions & 0 deletions pkg/apis/policy/v1alpha1/deep_copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package v1alpha1

import (
"fmt"
)

func deepCopy(in any) any {
if in == nil {
return nil
}
switch in := in.(type) {
case string:
return in
case int:
return in
case int32:
return in
case int64:
return in
case float32:
return in
case float64:
return in
case bool:
return in
case []any:
var out []any
for _, in := range in {
out = append(out, deepCopy(in))
}
return out
case map[string]any:
out := map[string]any{}
for k, in := range in {
out[k] = deepCopy(in)
}
return out
}
panic(fmt.Sprintf("deep copy failed - unrecognized type %T", in))
}
20 changes: 12 additions & 8 deletions pkg/matching/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,12 @@ func MatchAssert(ctx context.Context, path *field.Path, match *v1alpha1.Assert,
var fails []Result
path := path.Child("any")
for i, assertion := range match.Any {
parsed, err := assert.Parse(ctx, path.Index(i).Child("check"), assertion.Check.Raw())
path := path.Index(i).Child("check")
parsed, err := assertion.Check.Assertion(ctx, path)
if err != nil {
return fails, err
}
checkFails, err := assert.Assert(ctx, path.Index(i).Child("check"), parsed, actual, bindings, opts...)
checkFails, err := assert.Assert(ctx, path, parsed, actual, bindings, opts...)
if err != nil {
return fails, err
}
Expand All @@ -76,11 +77,12 @@ func MatchAssert(ctx context.Context, path *field.Path, match *v1alpha1.Assert,
var fails []Result
path := path.Child("all")
for i, assertion := range match.All {
parsed, err := assert.Parse(ctx, path.Index(i).Child("check"), assertion.Check.Raw())
path.Index(i).Child("check")
parsed, err := assertion.Check.Assertion(ctx, path)
if err != nil {
return fails, err
}
checkFails, err := assert.Assert(ctx, path.Index(i).Child("check"), parsed, actual, bindings, opts...)
checkFails, err := assert.Assert(ctx, path, parsed, actual, bindings, opts...)
if err != nil {
return fails, err
}
Expand Down Expand Up @@ -126,11 +128,12 @@ func Match(ctx context.Context, path *field.Path, match *v1alpha1.Match, actual
func MatchAny(ctx context.Context, path *field.Path, assertions []v1alpha1.AssertionTree, actual any, bindings binding.Bindings, opts ...template.Option) (field.ErrorList, error) {
var errs field.ErrorList
for i, assertion := range assertions {
parsed, err := assert.Parse(ctx, path.Index(i), assertion.Raw())
path := path.Index(i)
assertion, err := assertion.Assertion(ctx, path)
if err != nil {
return errs, err
}
_errs, err := assert.Assert(ctx, path.Index(i), parsed, actual, bindings, opts...)
_errs, err := assert.Assert(ctx, path, assertion, actual, bindings, opts...)
if err != nil {
return errs, err
}
Expand All @@ -145,11 +148,12 @@ func MatchAny(ctx context.Context, path *field.Path, assertions []v1alpha1.Asser
func MatchAll(ctx context.Context, path *field.Path, assertions []v1alpha1.AssertionTree, actual any, bindings binding.Bindings, opts ...template.Option) (field.ErrorList, error) {
var errs field.ErrorList
for i, assertion := range assertions {
parsed, err := assert.Parse(ctx, path.Index(i), assertion.Raw())
path := path.Index(i)
assertion, err := assertion.Assertion(ctx, path)
if err != nil {
return errs, err
}
_errs, err := assert.Assert(ctx, path.Index(i), parsed, actual, bindings, opts...)
_errs, err := assert.Assert(ctx, path, assertion, actual, bindings, opts...)
if err != nil {
return errs, err
}
Expand Down
5 changes: 3 additions & 2 deletions website/apis/config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
hiddenMemberFields:
- TypeMeta
- value
- tree
- _value
- _tree
- _assertion

externalPackages:
- match: ^k8s\.io/apimachinery/pkg/apis/meta/v1\.Duration$
Expand Down

0 comments on commit 0e18bed

Please sign in to comment.