go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/k8s/list_images_test.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package k8s
     5  
     6  import (
     7  	"testing"
     8  
     9  	"go.mondoo.com/cnquery/motor/motorid/containerid"
    10  
    11  	"github.com/golang/mock/gomock"
    12  	"github.com/google/go-containerregistry/pkg/name"
    13  	"github.com/google/go-containerregistry/pkg/v1/remote"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  	"go.mondoo.com/cnquery/motor/providers/k8s"
    17  
    18  	corev1 "k8s.io/api/core/v1"
    19  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    20  )
    21  
    22  func TestListPodImage(t *testing.T) {
    23  	mockCtrl := gomock.NewController(t)
    24  	defer mockCtrl.Finish()
    25  
    26  	p := k8s.NewMockKubernetesProvider(mockCtrl)
    27  
    28  	// Seed namespaces
    29  	nss := []corev1.Namespace{
    30  		{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
    31  		{ObjectMeta: metav1.ObjectMeta{Name: "kube-system"}},
    32  	}
    33  	p.EXPECT().Namespaces().Return(nss, nil)
    34  
    35  	// Seed pods
    36  	pods1 := []*corev1.Pod{
    37  		{
    38  			ObjectMeta: metav1.ObjectMeta{Name: "nginx", Namespace: nss[0].Name},
    39  			Spec: corev1.PodSpec{
    40  				Containers: []corev1.Container{{Image: "nginx:1.22.0-alpine"}},
    41  			},
    42  		},
    43  		{
    44  			ObjectMeta: metav1.ObjectMeta{Name: "nginx2", Namespace: nss[0].Name},
    45  			Spec: corev1.PodSpec{
    46  				Containers: []corev1.Container{{Image: "nginx:1.22.0-alpine"}},
    47  			},
    48  		},
    49  	}
    50  
    51  	pods2 := []*corev1.Pod{
    52  		{
    53  			ObjectMeta: metav1.ObjectMeta{Name: "kube-proxy", Namespace: nss[1].Name},
    54  			Spec: corev1.PodSpec{
    55  				InitContainers: []corev1.Container{{Image: "k8s.gcr.io/kube-proxy:v1.23.3"}},
    56  				Containers:     []corev1.Container{{Image: "k8s.gcr.io/kube-proxy:v1.23.3"}},
    57  			},
    58  		},
    59  		{
    60  			ObjectMeta: metav1.ObjectMeta{Name: "kube-scheduler", Namespace: nss[1].Name},
    61  			Spec: corev1.PodSpec{
    62  				Containers: []corev1.Container{{Image: "k8s.gcr.io/kube-scheduler:v1.23.3"}},
    63  			},
    64  		},
    65  	}
    66  	p.EXPECT().Pods(nss[0]).Return(pods1, nil)
    67  	p.EXPECT().Pods(nss[1]).Return(pods2, nil)
    68  
    69  	// nginx's tags seem to change digests, so resolve it to figure out what is the correct one
    70  	ref, err := name.ParseReference("nginx:1.22.0-alpine", name.WeakValidation)
    71  	require.NoError(t, err)
    72  	desc, err := remote.Get(ref)
    73  	require.NoError(t, err)
    74  
    75  	imgDigest := desc.Digest.String()
    76  	repoName := ref.Context().Name()
    77  	imageUrl := repoName + "@" + containerid.ShortContainerImageID(imgDigest)
    78  
    79  	expectedAssetNames := []string{
    80  		imageUrl,
    81  		"k8s.gcr.io/kube-scheduler@32308abe86f7",
    82  		"k8s.gcr.io/kube-proxy@def87f007b49",
    83  	}
    84  
    85  	clusterIdentifier := "//platformid.api.mondoo.app/runtime/k8s/uid/e26043bb-8669-48a2-b684-b1e132198cdc"
    86  	ownershipDir := k8s.NewEmptyPlatformIdOwnershipDirectory(clusterIdentifier)
    87  	assets, err := ListPodImages(p, NamespaceFilterOpts{}, ownershipDir)
    88  	assert.NoError(t, err)
    89  
    90  	var assetNames []string
    91  	for _, a := range assets {
    92  		assetNames = append(assetNames, a.Name)
    93  	}
    94  
    95  	assert.ElementsMatch(t, expectedAssetNames, assetNames)
    96  }
    97  
    98  func TestListPodImage_FromStatus(t *testing.T) {
    99  	mockCtrl := gomock.NewController(t)
   100  	defer mockCtrl.Finish()
   101  
   102  	p := k8s.NewMockKubernetesProvider(mockCtrl)
   103  
   104  	// Seed namespaces
   105  	nss := []corev1.Namespace{
   106  		{ObjectMeta: metav1.ObjectMeta{Name: "default"}},
   107  		{ObjectMeta: metav1.ObjectMeta{Name: "kube-system"}},
   108  	}
   109  	p.EXPECT().Namespaces().Return(nss, nil)
   110  
   111  	// Seed pods
   112  	pods1 := []*corev1.Pod{
   113  		{
   114  			ObjectMeta: metav1.ObjectMeta{Name: "nginx", Namespace: nss[0].Name},
   115  			Spec: corev1.PodSpec{
   116  				Containers: []corev1.Container{{Image: "nginx:1.22.0-alpine"}},
   117  			},
   118  			Status: corev1.PodStatus{
   119  				ContainerStatuses: []corev1.ContainerStatus{
   120  					{
   121  						Image:   "nginx:1.22.0-alpine",
   122  						ImageID: "docker-pullable://nginx@sha256:f335d7436887b39393409261603fb248e0c385ec18997d866dd44f7e9b621096",
   123  					},
   124  				},
   125  			},
   126  		},
   127  		{
   128  			ObjectMeta: metav1.ObjectMeta{Name: "nginx2", Namespace: nss[0].Name},
   129  			Spec: corev1.PodSpec{
   130  				Containers: []corev1.Container{{Image: "nginx:1.22.0-alpine"}},
   131  			},
   132  			Status: corev1.PodStatus{
   133  				ContainerStatuses: []corev1.ContainerStatus{
   134  					{
   135  						Image:   "nginx:1.22.0-alpine",
   136  						ImageID: "docker-pullable://nginx@sha256:f335d7436887b39393409261603fb248e0c385ec18997d866dd44f7e9b621096",
   137  					},
   138  				},
   139  			},
   140  		},
   141  	}
   142  
   143  	pods2 := []*corev1.Pod{
   144  		{
   145  			ObjectMeta: metav1.ObjectMeta{Name: "kube-proxy", Namespace: nss[1].Name},
   146  			Spec: corev1.PodSpec{
   147  				InitContainers: []corev1.Container{{Image: "k8s.gcr.io/kube-proxy:v1.23.3"}},
   148  				Containers:     []corev1.Container{{Image: "k8s.gcr.io/kube-proxy:v1.23.3"}},
   149  			},
   150  			Status: corev1.PodStatus{
   151  				InitContainerStatuses: []corev1.ContainerStatus{
   152  					{
   153  						Image:   "k8s.gcr.io/kube-proxy:v1.23.3",
   154  						ImageID: "docker-pullable://k8s.gcr.io/kube-proxy@sha256:def87f007b49d50693aed83d4703d0e56c69ae286154b1c7a20cd1b3a320cf7c",
   155  					},
   156  				},
   157  				ContainerStatuses: []corev1.ContainerStatus{
   158  					{
   159  						Image:   "k8s.gcr.io/kube-proxy:v1.23.3",
   160  						ImageID: "docker-pullable://k8s.gcr.io/kube-proxy@sha256:def87f007b49d50693aed83d4703d0e56c69ae286154b1c7a20cd1b3a320cf7c",
   161  					},
   162  				},
   163  			},
   164  		},
   165  		{
   166  			ObjectMeta: metav1.ObjectMeta{Name: "kube-scheduler", Namespace: nss[1].Name},
   167  			Spec: corev1.PodSpec{
   168  				Containers: []corev1.Container{{Image: "k8s.gcr.io/kube-scheduler:v1.23.3"}},
   169  			},
   170  			Status: corev1.PodStatus{
   171  				ContainerStatuses: []corev1.ContainerStatus{
   172  					{
   173  						Image:   "k8s.gcr.io/kube-scheduler:v1.23.3",
   174  						ImageID: "docker-pullable://k8s.gcr.io/kube-scheduler@sha256:32308abe86f7415611ca86ee79dd0a73e74ebecb2f9e3eb85fc3a8e62f03d0e7",
   175  					},
   176  				},
   177  			},
   178  		},
   179  	}
   180  	p.EXPECT().Pods(nss[0]).Return(pods1, nil)
   181  	p.EXPECT().Pods(nss[1]).Return(pods2, nil)
   182  
   183  	expectedAssetNames := []string{
   184  		"index.docker.io/library/nginx@f335d7436887",
   185  		"k8s.gcr.io/kube-scheduler@32308abe86f7",
   186  		"k8s.gcr.io/kube-proxy@def87f007b49",
   187  	}
   188  
   189  	clusterIdentifier := "//platformid.api.mondoo.app/runtime/k8s/uid/e26043bb-8669-48a2-b684-b1e132198cdc"
   190  	ownershipDir := k8s.NewEmptyPlatformIdOwnershipDirectory(clusterIdentifier)
   191  	assets, err := ListPodImages(p, NamespaceFilterOpts{}, ownershipDir)
   192  	assert.NoError(t, err)
   193  
   194  	var assetNames []string
   195  	for _, a := range assets {
   196  		assetNames = append(assetNames, a.Name)
   197  	}
   198  
   199  	assert.ElementsMatch(t, expectedAssetNames, assetNames)
   200  }