Skip to content
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
2 changes: 1 addition & 1 deletion cmd/gator/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func run(cmd *cobra.Command, args []string) {
os.Exit(exitCode)
}

func enforceableFailure(results []*types.Result) bool {
func enforceableFailure(results []*test.GatorResult) bool {
for _, result := range results {
if result.EnforcementAction == string(util.Deny) {
return true
Expand Down
17 changes: 11 additions & 6 deletions pkg/gator/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
templatesv1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/local"
"github.com/open-policy-agent/frameworks/constraint/pkg/types"
"github.com/open-policy-agent/gatekeeper/pkg/expansion"
"github.com/open-policy-agent/gatekeeper/pkg/gator"
mutationtypes "github.com/open-policy-agent/gatekeeper/pkg/mutation/types"
Expand All @@ -27,7 +26,7 @@ func init() {
}
}

func Test(objs []*unstructured.Unstructured) (*types.Responses, error) {
func Test(objs []*unstructured.Unstructured) (*GatorResponses, error) {
// create the client

driver, err := local.New(local.Tracing(false))
Expand Down Expand Up @@ -86,8 +85,8 @@ func Test(objs []*unstructured.Unstructured) (*types.Responses, error) {
}

// now audit all objects
responses := &types.Responses{
ByTarget: make(map[string]*types.Response),
responses := &GatorResponses{
ByTarget: make(map[string]*GatorResponse),
}
for _, obj := range objs {
// Try to attach the namespace if it was supplied (ns will be nil otherwise)
Expand Down Expand Up @@ -126,11 +125,17 @@ func Test(objs []*unstructured.Unstructured) (*types.Responses, error) {
for targetName, r := range review.ByTarget {
targetResponse := responses.ByTarget[targetName]
if targetResponse == nil {
targetResponse = &types.Response{}
targetResponse = &GatorResponse{}
targetResponse.Target = targetName
}

targetResponse.Results = append(targetResponse.Results, r.Results...)
// convert framework results to gator results, which contain a
// reference to the violating resource
gResults := make([]*GatorResult, len(r.Results))
for i, r := range r.Results {
gResults[i] = fromFrameworkResult(r, obj)
}
targetResponse.Results = append(targetResponse.Results, gResults...)

if r.Trace != nil {
var trace string
Expand Down
51 changes: 30 additions & 21 deletions pkg/gator/test/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestTest(t *testing.T) {
tcs := []struct {
name string
inputs []string
want []*types.Result
want []*GatorResult
err error
}{
{
Expand All @@ -78,21 +78,27 @@ func TestTest(t *testing.T) {
fixtures.ConstraintNeverValidate,
fixtures.Object,
},
want: []*types.Result{
want: []*GatorResult{
{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
Result: types.Result{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
},
},
{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
Result: types.Result{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
},
},
{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
Result: types.Result{
Target: target.Name,
Msg: "never validate",
Constraint: constraintNeverValidate,
},
},
},
},
Expand All @@ -104,16 +110,20 @@ func TestTest(t *testing.T) {
fixtures.ObjectReferentialInventory,
fixtures.ObjectReferentialDeny,
},
want: []*types.Result{
want: []*GatorResult{
{
Target: target.Name,
Msg: "same selector as service <gatekeeper-test-service-disallowed> in namespace <default>",
Constraint: constraintReferential,
Result: types.Result{
Target: target.Name,
Msg: "same selector as service <gatekeeper-test-service-disallowed> in namespace <default>",
Constraint: constraintReferential,
},
},
{
Target: target.Name,
Msg: "same selector as service <gatekeeper-test-service-example> in namespace <default>",
Constraint: constraintReferential,
Result: types.Result{
Target: target.Name,
Msg: "same selector as service <gatekeeper-test-service-example> in namespace <default>",
Constraint: constraintReferential,
},
},
},
},
Expand Down Expand Up @@ -166,7 +176,6 @@ func TestTest(t *testing.T) {

resps, err := Test(objs)
if tc.err != nil {
// If we're checking for specific errors, use errors.Is() to verify
if err == nil {
t.Errorf("got nil err, want %v", tc.err)
}
Expand All @@ -179,9 +188,9 @@ func TestTest(t *testing.T) {

got := resps.Results()

diff := cmp.Diff(tc.want, got, cmpopts.IgnoreFields(types.Result{}, "Metadata", "EnforcementAction"))
diff := cmp.Diff(tc.want, got, cmpopts.IgnoreFields(GatorResult{}, "Metadata", "EnforcementAction", "ViolatingObject"))
if diff != "" {
t.Errorf("diff in Result objects (-want +got):\n%s", diff)
t.Errorf("diff in GatorResult objects (-want +got):\n%s", diff)
}
})
}
Expand Down
66 changes: 66 additions & 0 deletions pkg/gator/test/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package test

import (
"sort"

"github.com/open-policy-agent/frameworks/constraint/pkg/types"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

type GatorResult struct {
types.Result

ViolatingObject *unstructured.Unstructured
}

func fromFrameworkResult(frameResult *types.Result, violatingObject *unstructured.Unstructured) *GatorResult {
gResult := &GatorResult{Result: *frameResult}

// do a deep copy to detach us from the Constraint Framework's references
gResult.Constraint = frameResult.Constraint.DeepCopy()

// set the violating object, which is no longer part of framework results
gResult.ViolatingObject = violatingObject

return gResult
}

// Response is a collection of Constraint violations for a particular Target.
// Each Result is for a distinct Constraint.
type GatorResponse struct {
Trace *string
Target string
Results []*GatorResult
}

type GatorResponses struct {
ByTarget map[string]*GatorResponse
Handled map[string]bool
}

func (r *GatorResponses) Results() []*GatorResult {
if r == nil {
return nil
}

var res []*GatorResult
for target, resp := range r.ByTarget {
for _, rr := range resp.Results {
rr.Target = target
res = append(res, rr)
}
}

// Make results more (but not completely) deterministic.
// After we shard Rego compilation environments, we will be able to tie
// responses to individual constraints. This is a stopgap to make tests easier
// to write until then.
sort.Slice(res, func(i, j int) bool {
if res[i].EnforcementAction != res[j].EnforcementAction {
return res[i].EnforcementAction < res[j].EnforcementAction
}
return res[i].Msg < res[j].Msg
})

return res
}