Skip to content

Commit

Permalink
feat: contextualize check
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 committed Sep 12, 2024
1 parent 74cdc8e commit b457b06
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 110 deletions.
6 changes: 6 additions & 0 deletions .crds/json.kyverno.io_validatingpolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ spec:
message:
description: Message is the message associated message.
type: string
with:
description: With defines the data to work with.
type: string
required:
- check
type: object
Expand All @@ -79,6 +82,9 @@ spec:
message:
description: Message is the message associated message.
type: string
with:
description: With defines the data to work with.
type: string
required:
- check
type: object
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/policy/v1alpha1/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package v1alpha1

// Assertion contains an assertion tree associated with a message.
type Assertion struct {
// With defines the data to work with.
// +optional
With string `json:"with,omitempty"`

// Message is the message associated message.
// +optional
Message string `json:"message,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions pkg/data/crds/json.kyverno.io_validatingpolicies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ spec:
message:
description: Message is the message associated message.
type: string
with:
description: With defines the data to work with.
type: string
required:
- check
type: object
Expand All @@ -79,6 +82,9 @@ spec:
message:
description: Message is the message associated message.
type: string
with:
description: With defines the data to work with.
type: string
required:
- check
type: object
Expand Down
6 changes: 3 additions & 3 deletions pkg/engine/assert/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import (
func NewContextBinding(path *field.Path, bindings binding.Bindings, value any, entry any) binding.Binding {
return template.NewLazyBinding(
func() (any, error) {
expression := parseExpression(context.TODO(), entry)
expression := ParseExpression(context.TODO(), entry)

Check warning on line 14 in pkg/engine/assert/binding.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/binding.go#L14

Added line #L14 was not covered by tests
if expression != nil && expression.engine != "" {
if expression.foreach {
if expression.Foreach {

Check warning on line 16 in pkg/engine/assert/binding.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/binding.go#L16

Added line #L16 was not covered by tests
return nil, field.Invalid(path.Child("variable"), entry, "foreach is not supported in context")
}
if expression.binding != "" {
return nil, field.Invalid(path.Child("variable"), entry, "binding is not supported in context")
}
projected, err := template.Execute(context.Background(), expression.statement, value, bindings)
projected, err := template.Execute(context.Background(), expression.Statement, value, bindings)

Check warning on line 22 in pkg/engine/assert/binding.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/binding.go#L22

Added line #L22 was not covered by tests
if err != nil {
return nil, field.InternalError(path.Child("variable"), err)
}
Expand Down
22 changes: 11 additions & 11 deletions pkg/engine/assert/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ var (
engineRegex = regexp.MustCompile(`^\((?:(\w+):)?(.+)\)$`)
)

type expression struct {
foreach bool
foreachName string
statement string
type Expression struct {
Foreach bool
ForeachName string
Statement string
binding string
engine string
}

func parseExpressionRegex(_ context.Context, in string) *expression {
expression := &expression{}
func parseExpressionRegex(_ context.Context, in string) *Expression {
expression := &Expression{}
// 1. match foreach
if match := foreachRegex.FindStringSubmatch(in); match != nil {
expression.foreach = true
expression.foreachName = match[1]
expression.Foreach = true
expression.ForeachName = match[1]
in = match[2]
}
// 2. match binding
Expand All @@ -50,14 +50,14 @@ func parseExpressionRegex(_ context.Context, in string) *expression {
}
}
// parse statement
expression.statement = in
if expression.statement == "" {
expression.Statement = in
if expression.Statement == "" {
return nil
}
return expression
}

func parseExpression(ctx context.Context, value any) *expression {
func ParseExpression(ctx context.Context, value any) *Expression {
if reflectutils.GetKind(value) != reflect.String {
return nil
}
Expand Down
138 changes: 69 additions & 69 deletions pkg/engine/assert/expression_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,161 +11,161 @@ func Test_parseExpressionRegex(t *testing.T) {
tests := []struct {
name string
in string
want *expression
want *Expression
}{{
name: "empty",
in: "",
want: nil,
}, {
name: "simple field",
in: "test",
want: &expression{
foreach: false,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test",
},
}, {
name: "simple field",
in: "(test)",
want: &expression{
foreach: false,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test",
engine: "jp",
},
}, {
name: "nested field",
in: "test.test",
want: &expression{
foreach: false,
foreachName: "",
statement: "test.test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test.test",
},
}, {
name: "nested field",
in: "(test.test)",
want: &expression{
foreach: false,
foreachName: "",
statement: "test.test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test.test",
engine: "jp",
},
}, {
name: "foreach simple field",
in: "~.test",
want: &expression{
foreach: true,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: true,
ForeachName: "",
Statement: "test",
},
}, {
name: "foreach simple field",
in: "~.(test)",
want: &expression{
foreach: true,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: true,
ForeachName: "",
Statement: "test",
engine: "jp",
},
}, {
name: "foreach nested field",
in: "~.(test.test)",
want: &expression{
foreach: true,
foreachName: "",
statement: "test.test",
want: &Expression{
Foreach: true,
ForeachName: "",
Statement: "test.test",
engine: "jp",
},
}, {
name: "binding",
in: "test->foo",
want: &expression{
foreach: false,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test",
binding: "foo",
},
}, {
name: "binding",
in: "(test)->foo",
want: &expression{
foreach: false,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test",
binding: "foo",
engine: "jp",
},
}, {
name: "foreach and binding",
in: "~.test->foo",
want: &expression{
foreach: true,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: true,
ForeachName: "",
Statement: "test",
binding: "foo",
},
}, {
name: "foreach and binding",
in: "~.(test)->foo",
want: &expression{
foreach: true,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: true,
ForeachName: "",
Statement: "test",
binding: "foo",
engine: "jp",
},
}, {
name: "escape",
in: `\~(test)->foo\`,
want: &expression{
foreach: false,
foreachName: "",
statement: "~(test)->foo",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "~(test)->foo",
binding: "",
},
}, {
name: "escape",
in: `\test\`,
want: &expression{
foreach: false,
foreachName: "",
statement: "test",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "test",
binding: "",
},
}, {
name: "escape",
in: `\(test)\`,
want: &expression{
foreach: false,
foreachName: "",
statement: "(test)",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "(test)",
binding: "",
},
}, {
name: "escape",
in: `\/test/\`,
want: &expression{
foreach: false,
foreachName: "",
statement: "/test/",
want: &Expression{
Foreach: false,
ForeachName: "",
Statement: "/test/",
binding: "",
},
}, {
name: "escape",
in: `~index.\(test)\`,
want: &expression{
foreach: true,
foreachName: "index",
statement: "(test)",
want: &Expression{
Foreach: true,
ForeachName: "index",
Statement: "(test)",
binding: "",
},
}, {
name: "escape",
in: `~index.\(test)\->name`,
want: &expression{
foreach: true,
foreachName: "index",
statement: "(test)",
want: &Expression{
Foreach: true,
ForeachName: "index",
Statement: "(test)",
binding: "name",
},
}}
Expand Down
6 changes: 3 additions & 3 deletions pkg/engine/assert/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,17 @@ type scalarNode struct {

func (n *scalarNode) assert(ctx context.Context, path *field.Path, value any, bindings binding.Bindings, opts ...template.Option) (field.ErrorList, error) {
rhs := n.rhs
expression := parseExpression(ctx, rhs)
expression := ParseExpression(ctx, rhs)

Check warning on line 141 in pkg/engine/assert/parse.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/parse.go#L141

Added line #L141 was not covered by tests
// we only project if the expression uses the engine syntax
// this is to avoid the case where the value is a map and the RHS is a string
if expression != nil && expression.engine != "" {
if expression.foreachName != "" {
if expression.ForeachName != "" {

Check warning on line 145 in pkg/engine/assert/parse.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/parse.go#L145

Added line #L145 was not covered by tests
return nil, field.Invalid(path, rhs, "foreach is not supported on the RHS")
}
if expression.binding != "" {
return nil, field.Invalid(path, rhs, "binding is not supported on the RHS")
}
projected, err := template.Execute(ctx, expression.statement, value, bindings, opts...)
projected, err := template.Execute(ctx, expression.Statement, value, bindings, opts...)

Check warning on line 151 in pkg/engine/assert/parse.go

View check run for this annotation

Codecov / codecov/patch

pkg/engine/assert/parse.go#L151

Added line #L151 was not covered by tests
if err != nil {
return nil, field.InternalError(path, err)
}
Expand Down
Loading

0 comments on commit b457b06

Please sign in to comment.