Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle namespaceselector and empty namespaces #26

Merged
merged 5 commits into from
Jul 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions constraint/Gopkg.lock

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

24 changes: 22 additions & 2 deletions constraint/config/crds/templates_v1alpha1_constrainttemplate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,30 @@ spec:
type: object
status:
properties:
byPod:
items:
properties:
errors:
items:
properties:
code:
type: string
location:
type: string
message:
type: string
required:
- code
- message
type: object
type: array
id:
description: a unique identifier for the pod that wrote the status
type: string
type: object
type: array
created:
type: boolean
error:
type: string
type: object
version: v1alpha1
status:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,23 @@ type Target struct {

// CreateCRDError represents a single error caught during parsing, compiling, etc.
type CreateCRDError struct {
Code string `json:"code"`
Code string `json:"code"`
Message string `json:"message"`
Location string `json:"location,omitempty"`
Location string `json:"location,omitempty"`
}

// ByPodStatus defines the observed state of ConstraintTemplate as seen by
// an individual controller
type ByPodStatus struct {
// a unique identifier for the pod that wrote the status
ID string `json:"id,omitempty"`
Errors []*CreateCRDError `json:"errors,omitempty"`
ID string `json:"id,omitempty"`
Errors []*CreateCRDError `json:"errors,omitempty"`
}

// ConstraintTemplateStatus defines the observed state of ConstraintTemplate
type ConstraintTemplateStatus struct {
Created bool `json:"created,omitempty"`
ByPod []*ByPodStatus `json:"byPod,omitempty"`
Created bool `json:"created,omitempty"`
ByPod []*ByPodStatus `json:"byPod,omitempty"`
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
}
Expand Down
1 change: 1 addition & 0 deletions constraint/pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ func (c *client) init() error {
}
lib := libBuf.String()
req := ruleArities{
"autoreject_review": 1,
"matching_reviews_and_constraints": 2,
"matching_constraints": 1,
}
Expand Down
1 change: 1 addition & 0 deletions constraint/pkg/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func (h *badHandler) Library() *template.Template {
}
return template.Must(template.New("foo").Parse(`
package foo
autoreject_review[r] {r = data.r}
matching_constraints[c] {c = data.c}
matching_reviews_and_constraints[[r,c]] {r = data.r; c = data.c}`))
}
Expand Down
66 changes: 66 additions & 0 deletions constraint/pkg/client/e2e_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"context"
"encoding/json"
"fmt"
"reflect"
"strings"
Expand Down Expand Up @@ -180,6 +181,71 @@ violation[{"msg": "DENIED", "details": {}}] {
return nil
},

"Autoreject All": func(c Client) error {
_, err := c.AddTemplate(ctx, newConstraintTemplate("Foo", `package foo
violation[{"msg": "DENIED", "details": {}}] {
"always" == "always"
}`))
if err != nil {
return errors.Wrap(err, "AddTemplate")
}
goodNamespaceSelectorConstraint := `
{
"apiVersion": "constraints.gatekeeper.sh/v1alpha1",
"kind": "Foo",
"metadata": {
"name": "foo-pod"
},
"spec": {
"match": {
"kinds": [
{
"apiGroups": [""],
"kinds": ["Pod"]
}],
"namespaceSelector": {
"matchExpressions": [{
"key": "someKey",
"operator": "Blah",
"values": ["some value"]
}]
}
},
"parameters": {
"key": ["value"]
}
}
}
`
u := &unstructured.Unstructured{}
err = json.Unmarshal([]byte(goodNamespaceSelectorConstraint), u)
if err != nil {
return errors.Wrap(err, "Unable to parse constraint JSON")
}
if _, err := c.AddConstraint(ctx, u); err != nil {
return errors.Wrap(err, "AddConstraint")
}
rsps, err := c.Review(ctx, targetData{Name: "Sara", ForConstraint: "Foo"})
if err != nil {
return errors.Wrap(err, "Review")
}
if len(rsps.ByTarget) == 0 {
return errors.New("No responses returned")
}
if len(rsps.Results()) != 2 {
return e("Bad number of results", rsps)
}
if rsps.Results()[0].Msg != "REJECTION" && rsps.Results()[1].Msg != "REJECTION" {
return e(fmt.Sprintf("res.Msg = %s; wanted at least one REJECTION", rsps.Results()[0].Msg), rsps)
}
for _, r := range rsps.Results() {
if r.Msg == "REJECTION" && !reflect.DeepEqual(r.Constraint, u) {
return e(fmt.Sprintf("Constraint %s != %s", spew.Sdump(r.Constraint), spew.Sdump(u)), rsps)
}
}
return nil
},

"Remove Data": func(c Client) error {
_, err := c.AddTemplate(ctx, newConstraintTemplate("Foo", `package foo
violation[{"msg": "DENIED", "details": {}}] {
Expand Down
11 changes: 11 additions & 0 deletions constraint/pkg/client/regolib/src.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ const (
targetLibSrc = `
package hooks["{{.Target}}"]

violation[response] {
data.hooks["{{.Target}}"].library.autoreject_review[rejection]
review := get_default(input, "review", {})
response = {
ritazh marked this conversation as resolved.
Show resolved Hide resolved
"msg": get_default(rejection, "msg", ""),
"metadata": {"details": get_default(rejection, "details", {})},
"constraint": get_default(rejection, "constraint", {}),
"review": review,
}
}

# Finds all violations for a given target
violation[response] {
data.hooks["{{.Target}}"].library.matching_constraints[constraint]
Expand Down
37 changes: 37 additions & 0 deletions constraint/pkg/client/test_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ func (h *handler) GetName() string {
var libTempl = template.Must(template.New("library").Parse(`
package foo

autoreject_review[rejection] {
constraint := {{.ConstraintsRoot}}[_][_]
spec := get_default(constraint, "spec", {})
match := get_default(spec, "match", {})
has_field(match, "namespaceSelector")
not {{.DataRoot}}.cluster["v1"]["Namespace"]
rejection := {
"msg": "REJECTION",
"details": {},
"constraint": constraint,
}
}

matching_constraints[constraint] {
constraint = {{.ConstraintsRoot}}[input.review.ForConstraint][_]
}
Expand All @@ -28,6 +41,30 @@ matching_reviews_and_constraints[[review, constraint]] {
matching_constraints[constraint] with input as {"review": review}
review = {{.DataRoot}}[_]
}

has_field(object, field) = true {
object[field]
}

has_field(object, field) = true {
object[field] == false
}

has_field(object, field) = false {
not object[field]
not object[field] == false
}

get_default(object, field, _default) = output {
has_field(object, field)
output = object[field]
}

get_default(object, field, _default) = output {
has_field(object, field) == false
output = _default
}

`))

func (h *handler) Library() *template.Template {
Expand Down
46 changes: 43 additions & 3 deletions constraint/vendor/github.com/open-policy-agent/opa/ast/builtins.go

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

14 changes: 10 additions & 4 deletions constraint/vendor/github.com/open-policy-agent/opa/ast/compare.go

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

Loading