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 }