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
7 changes: 6 additions & 1 deletion mainhandler/handlerequests.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,12 @@ func (mainHandler *MainHandler) HandleImageScanningScopedRequest(ctx context.Con

func (mainHandler *MainHandler) getNamespaces(ctx context.Context, sessionObj *utils.SessionObj) ([]string, error) {
namespaces := make([]string, 0, 1)
namespaces = append(namespaces, pkgwlid.GetNamespaceFromWlid(sessionObj.Command.GetID()))
// A cluster-wide request has no namespace in its ID. Leaving the list empty makes every
// namespace be listed below, so each one is filtered and looked up on its own instead of
// as "".
if ns := pkgwlid.GetNamespaceFromWlid(sessionObj.Command.GetID()); ns != "" {
namespaces = append(namespaces, ns)
}
if len(sessionObj.Command.Designators) > 0 {
namespaces = make([]string, 0, 3)
for desiIdx := range sessionObj.Command.Designators {
Expand Down
78 changes: 78 additions & 0 deletions mainhandler/scoped_cluster_wide_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package mainhandler

import (
"context"
"testing"

"github.com/armosec/armoapi-go/apis"
pkgwlid "github.com/armosec/utils-k8s-go/wlid"
"github.com/kubescape/operator/config"
"github.com/kubescape/operator/utils"
kssfake "github.com/kubescape/storage/pkg/generated/clientset/versioned/fake"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sfake "k8s.io/client-go/kubernetes/fake"
clienttesting "k8s.io/client-go/testing"
)

// clusterWideImageScan is a cluster-wide image scan request, as the SecurityException
// watcher sends for its image rescans: a WildWlid that names the cluster and no namespace.
func clusterWideImageScan() *utils.SessionObj {
return &utils.SessionObj{Command: &apis.Command{
CommandName: apis.TypeScanImages,
WildWlid: pkgwlid.GetK8sWLID("cluster", "", "", ""),
}}
}

func namespaceForHandler(name string) *corev1.Namespace {
return &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: name}}
}

// TestHandleImageScanningScopedRequest_ClusterWideLooksUpProfilesInPodNamespace checks that a
// cluster-wide request looks each pod's ContainerProfile up in the pod's own namespace. With
// the empty namespace of the request, a real client refuses the Get ("an empty namespace may
// not be set when a resource name is provided"), so no relevancy scan was ever started.
func TestHandleImageScanningScopedRequest_ClusterWideLooksUpProfilesInPodNamespace(t *testing.T) {
ns := "default"
pod := nakedRunningPodForHandler(ns, "my-pod", []string{"nginx"})
slugs := withContainerSlugsForHandler(t, pod)
require.Len(t, slugs, 1)

k8sClient := k8sfake.NewClientset(namespaceForHandler(ns), pod)
storageClient := kssfake.NewClientset(containerProfileForHandler(ns, slugs[0]))
scanner := newScannerStub(t)
mainHandler := newMainHandlerForTest(k8sClient, storageClient, scanner)

mainHandler.HandleImageScanningScopedRequest(context.Background(), clusterWideImageScan())

var lookedUpIn []string
for _, action := range storageClient.Actions() {
if action.Matches("get", "containerprofiles") {
lookedUpIn = append(lookedUpIn, action.(clienttesting.GetAction).GetNamespace())
}
}
assert.Equal(t, []string{ns}, lookedUpIn, "the ContainerProfile must be looked up in the pod's namespace")
assert.Equal(t, 1, scanner.requestCount())
}

// TestHandleImageScanningScopedRequest_ClusterWideHonoursIncludedNamespaces checks that the
// namespace filter applies to the namespaces a cluster-wide request covers, not to the
// request's own empty namespace, which no include list contains.
func TestHandleImageScanningScopedRequest_ClusterWideHonoursIncludedNamespaces(t *testing.T) {
included := nakedRunningPodForHandler("payments", "api", []string{"nginx"})
other := nakedRunningPodForHandler("other", "worker", []string{"nginx"})

k8sClient := k8sfake.NewClientset(namespaceForHandler("payments"), namespaceForHandler("other"), included, other)
scanner := newScannerStub(t)
mainHandler := newMainHandlerForTest(k8sClient, kssfake.NewClientset(), scanner)
cfg, ok := mainHandler.config.(*config.OperatorConfig)
require.True(t, ok)
_, err := cfg.UpdateNamespaceFilters([]byte(`{"includeNamespaces":["payments"],"excludeNamespaces":[]}`))
require.NoError(t, err)

mainHandler.HandleImageScanningScopedRequest(context.Background(), clusterWideImageScan())

assert.Equal(t, 1, scanner.requestCount(), "only the pod in the included namespace is scanned")
}
Loading