Skip to content
Open
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
46 changes: 44 additions & 2 deletions pkg/booleanpolicy/filter/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,51 @@ import (
// nil. Every filter in the returned slice is guaranteed to be non-default
// (i.e. IsNonDefault() == true), so callers can treat a non-empty slice as
// an indication that filtering is active.
func CompileEvaluationFilter(_ *storage.EvaluationFilter) []EvaluationFilter {
func CompileEvaluationFilter(proto *storage.EvaluationFilter) []EvaluationFilter {
if !features.EvaluationFilter.Enabled() {
return nil
}
return nil
var filters []EvaluationFilter
if f := newContainerTypeFilter(proto.GetSkipContainerTypes()); f != nil {
filters = append(filters, *f)
}
return filters
}

func newContainerTypeFilter(skipTypes []storage.ContainerType) *EvaluationFilter {
if len(skipTypes) == 0 {
return nil
}
skip := make(map[storage.ContainerType]struct{}, len(skipTypes))
for _, t := range skipTypes {
skip[t] = struct{}{}
}
return &EvaluationFilter{
isNonDefault: func() bool { return true },
apply: func(dep *storage.Deployment, imgs []*storage.Image) (*storage.Deployment, []*storage.Image) {
hasSkipped := false
for _, c := range dep.GetContainers() {
if _, ok := skip[c.GetType()]; ok {
hasSkipped = true
break
}
}
if !hasSkipped {
return dep, imgs
}
filtered := dep.CloneVT()
filtered.Containers = nil
var filteredImgs []*storage.Image
for i, c := range dep.GetContainers() {
if _, ok := skip[c.GetType()]; ok {
continue
}
filtered.Containers = append(filtered.Containers, c)
if i < len(imgs) {
filteredImgs = append(filteredImgs, imgs[i])
}
}
return filtered, filteredImgs
},
}
}
89 changes: 89 additions & 0 deletions pkg/booleanpolicy/filter/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/features"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCompileEvaluationFilter_AllFiltersAreNonDefault(t *testing.T) {
Expand All @@ -26,3 +27,91 @@ func TestCompileEvaluationFilter_DisabledFeatureReturnsNil(t *testing.T) {
t.Setenv(features.EvaluationFilter.EnvVar(), "false")
assert.Nil(t, CompileEvaluationFilter(&storage.EvaluationFilter{}))
}

func TestCompileEvaluationFilter_NoSkipTypes_ReturnsNil(t *testing.T) {
t.Setenv(features.EvaluationFilter.EnvVar(), "true")
assert.Nil(t, CompileEvaluationFilter(nil))
assert.Nil(t, CompileEvaluationFilter(&storage.EvaluationFilter{}))
}

func TestCompileEvaluationFilter_ContainerTypeFilter(t *testing.T) {
tests := map[string]struct {
skipTypes []storage.ContainerType
containers []*storage.Container
images []*storage.Image
expectedContainers []string
expectedImages []string
expectSamePointer bool
}{
"skip init containers": {
skipTypes: []storage.ContainerType{storage.ContainerType_INIT},
containers: []*storage.Container{
{Name: "init-setup", Type: storage.ContainerType_INIT},
{Name: "app", Type: storage.ContainerType_REGULAR},
{Name: "init-db", Type: storage.ContainerType_INIT},
{Name: "sidecar", Type: storage.ContainerType_REGULAR},
},
images: []*storage.Image{
{Id: "init-setup-img"},
{Id: "app-img"},
{Id: "init-db-img"},
{Id: "sidecar-img"},
},
expectedContainers: []string{"app", "sidecar"},
expectedImages: []string{"app-img", "sidecar-img"},
},
"skip init but none present returns original": {
skipTypes: []storage.ContainerType{storage.ContainerType_INIT},
containers: []*storage.Container{
{Name: "app", Type: storage.ContainerType_REGULAR},
},
images: []*storage.Image{{Id: "app-img"}},
expectSamePointer: true,
},
"skip regular containers": {
skipTypes: []storage.ContainerType{storage.ContainerType_REGULAR},
containers: []*storage.Container{
{Name: "init-setup", Type: storage.ContainerType_INIT},
{Name: "app", Type: storage.ContainerType_REGULAR},
},
images: []*storage.Image{
{Id: "init-img"},
{Id: "app-img"},
},
expectedContainers: []string{"init-setup"},
expectedImages: []string{"init-img"},
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
t.Setenv(features.EvaluationFilter.EnvVar(), "true")

filters := CompileEvaluationFilter(&storage.EvaluationFilter{
SkipContainerTypes: tc.skipTypes,
})
require.Len(t, filters, 1)
assert.True(t, filters[0].IsNonDefault())

dep := &storage.Deployment{Containers: tc.containers}
resultDep, resultImgs := filters[0].Apply(dep, tc.images)

if tc.expectSamePointer {
assert.True(t, dep == resultDep, "expected same deployment pointer when no filtering needed")
return
}

require.Len(t, resultDep.GetContainers(), len(tc.expectedContainers))
for i, name := range tc.expectedContainers {
assert.Equal(t, name, resultDep.GetContainers()[i].GetName())
}
require.Len(t, resultImgs, len(tc.expectedImages))
for i, id := range tc.expectedImages {
assert.Equal(t, id, resultImgs[i].GetId())
}

// Original not mutated.
assert.Len(t, dep.GetContainers(), len(tc.containers))
})
}
}
Loading