Skip to content

Commit

Permalink
Add pathtest functionality to assign mutators (#1101)
Browse files Browse the repository at this point in the history
* Add pathtest functionality to assign mutators

Signed-off-by: Max Smythe <smythe@google.com>

* Add locking, deepcopy path tester memoization

Signed-off-by: Max Smythe <smythe@google.com>

* Add path parsing error context

Signed-off-by: Max Smythe <smythe@google.com>

* Tester should also have a DeepCopy method

Signed-off-by: Max Smythe <smythe@google.com>

* Eager initialize path tester, guard against nil

Signed-off-by: Max Smythe <smythe@google.com>
  • Loading branch information
maxsmythe committed Feb 9, 2021
1 parent 9d424ff commit e8ed13c
Show file tree
Hide file tree
Showing 10 changed files with 1,192 additions and 141 deletions.
8 changes: 3 additions & 5 deletions apis/mutations/v1alpha1/assign_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package v1alpha1

import (
"github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
Expand Down Expand Up @@ -52,9 +53,6 @@ type Parameters struct {
Assign runtime.RawExtension `json:"assign,omitempty"`
}

// +kubebuilder:validation:Enum=MustExist;MustNotExist
type Condition string

// PathTests allows the user to customize how the mutation works if parent
// paths are missing. It traverses the list in order. All sub paths are
// tested against the provided condition, if the test fails, the mutation is
Expand All @@ -66,8 +64,8 @@ type Condition string
// * MustExist - the path must exist or do not mutate
// * MustNotExist - the path must not exist or do not mutate
type PathTest struct {
SubPath string `json:"subPath,omitempty"`
Condition Condition `json:"condition,omitempty"`
SubPath string `json:"subPath,omitempty"`
Condition tester.Condition `json:"condition,omitempty"`
}

// AssignStatus defines the observed state of Assign
Expand Down
2 changes: 1 addition & 1 deletion apis/mutations/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions config/crd/bases/mutations.gatekeeper.sh_assign.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ spec:
not exist or do not mutate"
properties:
condition:
description: Condition describes whether the path either MustExist
or MustNotExist in the original object
enum:
- MustExist
- MustNotExist
Expand Down
36 changes: 35 additions & 1 deletion pkg/mutation/assign_mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/google/go-cmp/cmp"
mutationsv1alpha1 "github.com/open-policy-agent/gatekeeper/apis/mutations/v1alpha1"
"github.com/open-policy-agent/gatekeeper/pkg/mutation/path/parser"
patht "github.com/open-policy-agent/gatekeeper/pkg/mutation/path/tester"
"github.com/open-policy-agent/gatekeeper/pkg/mutation/schema"
"github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
"github.com/pkg/errors"
Expand All @@ -23,6 +24,7 @@ type AssignMutator struct {
assign *mutationsv1alpha1.Assign
path *parser.Path
bindings []schema.Binding
tester *patht.Tester
}

// AssignMutator implements mutatorWithSchema
Expand All @@ -38,7 +40,7 @@ func (m *AssignMutator) Matches(obj runtime.Object, ns *corev1.Namespace) bool {
}

func (m *AssignMutator) Mutate(obj *unstructured.Unstructured) error {
return Mutate(m, obj)
return mutate(m, m.tester, obj)
}
func (m *AssignMutator) ID() types.ID {
return m.id
Expand Down Expand Up @@ -91,6 +93,7 @@ func (m *AssignMutator) DeepCopy() types.Mutator {
}
copy(res.path.Nodes, m.path.Nodes)
copy(res.bindings, m.bindings)
res.tester = m.tester.DeepCopy()
return res
}

Expand All @@ -107,14 +110,41 @@ func MutatorForAssign(assign *mutationsv1alpha1.Assign) (*AssignMutator, error)
return nil, errors.Wrap(err, "Failed to parse the location specified")
}

pathTests, err := gatherPathTests(assign)
if err != nil {
return nil, err
}
err = patht.ValidatePathTests(path, pathTests)
if err != nil {
return nil, err
}
tester, err := patht.New(pathTests)
if err != nil {
return nil, err
}

return &AssignMutator{
id: id,
assign: assign.DeepCopy(),
bindings: applyToToBindings(assign.Spec.ApplyTo),
path: path,
tester: tester,
}, nil
}

func gatherPathTests(assign *mutationsv1alpha1.Assign) ([]patht.Test, error) {
pts := assign.Spec.Parameters.PathTests
var pathTests []patht.Test
for _, pt := range pts {
p, err := parser.Parse(pt.SubPath)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("problem parsing sub path `%s`", pt.SubPath))
}
pathTests = append(pathTests, patht.Test{SubPath: p, Condition: pt.Condition})
}
return pathTests, nil
}

func applyToToBindings(applyTos []mutationsv1alpha1.ApplyTo) []schema.Binding {
res := []schema.Binding{}
for _, applyTo := range applyTos {
Expand Down Expand Up @@ -169,6 +199,10 @@ func IsValidAssign(assign *mutationsv1alpha1.Assign) error {
if err != nil {
return err
}
_, err = MutatorForAssign(assign)
if err != nil {
return err
}
return nil
}

Expand Down

0 comments on commit e8ed13c

Please sign in to comment.