go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/_motor/discovery/k8s/resolver_test.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package k8s 5 6 import ( 7 "context" 8 "encoding/base64" 9 "os" 10 "sort" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 "go.mondoo.com/cnquery/motor/asset" 16 "go.mondoo.com/cnquery/motor/providers" 17 "go.mondoo.com/cnquery/motor/providers/k8s" 18 "go.mondoo.com/cnquery/motor/providers/k8s/resources" 19 ) 20 21 func TestManifestResolver(t *testing.T) { 22 resolver := &Resolver{} 23 manifestFile := "../../providers/k8s/resources/testdata/pod.yaml" 24 25 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 26 27 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 28 PlatformId: "//platform/k8s/uid/123/namespace/default/pods/name/mondoo", 29 Backend: providers.ProviderType_K8S, 30 Options: map[string]string{ 31 "path": manifestFile, 32 }, 33 Discover: &providers.Discovery{ 34 Targets: []string{"all"}, 35 }, 36 }, nil, nil) 37 require.NoError(t, err) 38 assert.Equal(t, 4, len(assetList)) 39 assert.Equal(t, assetList[0].Platform.Name, "k8s-manifest") 40 assert.Equal(t, assetList[1].Platform.Name, "k8s-pod") 41 assert.Contains(t, assetList[1].Platform.Family, "k8s-workload") 42 assert.Contains(t, assetList[1].Platform.Family, "k8s") 43 assert.Equal(t, assetList[3].Platform.Runtime, "docker-registry") 44 } 45 46 func TestManifestResolver_NoNamespace(t *testing.T) { 47 resolver := &Resolver{} 48 manifestFile := "../../providers/k8s/resources/testdata/deployment-nons.yaml" 49 50 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 51 52 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 53 PlatformId: "//platform/k8s/uid/123/namespace/default/deployment/name/mondoo", 54 Backend: providers.ProviderType_K8S, 55 Options: map[string]string{ 56 "path": manifestFile, 57 }, 58 Discover: &providers.Discovery{ 59 Targets: []string{"all"}, 60 }, 61 }, nil, nil) 62 require.NoError(t, err) 63 assert.Equal(t, 2, len(assetList)) 64 assert.Equal(t, assetList[0].Platform.Name, "k8s-manifest") 65 assert.Equal(t, assetList[1].Platform.Name, "k8s-deployment") 66 assert.Contains(t, assetList[1].Platform.Family, "k8s-workload") 67 assert.Contains(t, assetList[1].Platform.Family, "k8s") 68 } 69 70 func TestAdmissionReviewResolver(t *testing.T) { 71 resolver := &Resolver{} 72 73 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 74 data, err := os.ReadFile("../../providers/k8s/resources/testdata/admission-review.json") 75 require.NoError(t, err) 76 77 admission := base64.StdEncoding.EncodeToString(data) 78 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 79 Backend: providers.ProviderType_K8S, 80 Options: map[string]string{ 81 k8s.OPTION_ADMISSION: admission, 82 }, 83 Discover: &providers.Discovery{ 84 Targets: []string{"all"}, 85 }, 86 }, nil, nil) 87 require.NoError(t, err) 88 assert.Equal(t, 4, len(assetList)) 89 assert.Equal(t, assetList[0].Platform.Name, "kubernetes") 90 assert.Equal(t, assetList[1].Platform.Name, "k8s-pod") 91 assert.Contains(t, assetList[1].Platform.Family, "k8s-workload") 92 assert.Contains(t, assetList[1].Platform.Family, "k8s") 93 assert.Equal(t, assetList[2].Platform.Runtime, "docker-registry") 94 assert.Equal(t, assetList[3].Platform.Runtime, "k8s-admission") 95 } 96 97 func TestManifestResolverDiscoveries(t *testing.T) { 98 testCases := []struct { 99 kind string 100 discoveryOption string 101 platformName string 102 expectedAssetNames []string 103 }{ 104 { 105 kind: "pod", 106 discoveryOption: "pods", 107 platformName: "k8s-pod", 108 expectedAssetNames: []string{"default/mondoo", "default/hello-pod-2"}, 109 }, 110 { 111 kind: "cronjob", 112 discoveryOption: "cronjobs", 113 platformName: "k8s-cronjob", 114 expectedAssetNames: []string{"default/mondoo"}, 115 }, 116 { 117 kind: "job", 118 discoveryOption: "jobs", 119 platformName: "k8s-job", 120 expectedAssetNames: []string{"default/mondoo"}, 121 }, 122 { 123 kind: "statefulset", 124 discoveryOption: "statefulsets", 125 platformName: "k8s-statefulset", 126 expectedAssetNames: []string{"default/mondoo"}, 127 }, 128 { 129 kind: "daemonset", 130 discoveryOption: "daemonsets", 131 platformName: "k8s-daemonset", 132 expectedAssetNames: []string{"default/mondoo"}, 133 }, 134 { 135 kind: "replicaset", 136 discoveryOption: "replicasets", 137 platformName: "k8s-replicaset", 138 expectedAssetNames: []string{"default/mondoo"}, 139 }, 140 { 141 kind: "deployment", 142 discoveryOption: "deployments", 143 platformName: "k8s-deployment", 144 expectedAssetNames: []string{"default/mondoo"}, 145 }, 146 } 147 148 for _, testCase := range testCases { 149 t.Run("discover k8s "+testCase.kind, func(t *testing.T) { 150 resolver := &Resolver{} 151 manifestFile := "../../providers/k8s/resources/testdata/" + testCase.kind + ".yaml" 152 153 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 154 155 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 156 PlatformId: "//platform/k8s/uid/123/namespace/default/" + testCase.discoveryOption + "/name/mondoo", 157 Backend: providers.ProviderType_K8S, 158 Options: map[string]string{ 159 "path": manifestFile, 160 }, 161 Discover: &providers.Discovery{ 162 Targets: []string{testCase.discoveryOption}, 163 }, 164 }, nil, nil) 165 require.NoError(t, err) 166 // When this check fails locally, check your kubeconfig. 167 // context has to reference the default namespace 168 assert.Equal(t, len(testCase.expectedAssetNames), len(assetList)) 169 170 for _, a := range assetList { 171 assert.Contains(t, a.Platform.Family, "k8s-workload") 172 assert.Contains(t, a.Platform.Family, "k8s") 173 assert.Equal(t, "k8s-manifest", a.Platform.Runtime) 174 assert.Equal(t, testCase.platformName, a.Platform.Name) 175 assert.Contains(t, testCase.expectedAssetNames, a.Name) 176 } 177 }) 178 } 179 } 180 181 func TestManifestResolverMultiPodDiscovery(t *testing.T) { 182 resolver := &Resolver{} 183 manifestFile := "../../providers/k8s/resources/testdata/pod.yaml" 184 185 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 186 187 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 188 PlatformId: "//platform/k8s/uid/123/namespace/default/pods/name/mondoo", 189 Backend: providers.ProviderType_K8S, 190 Options: map[string]string{ 191 "path": manifestFile, 192 }, 193 Discover: &providers.Discovery{ 194 Targets: []string{"pods"}, 195 }, 196 }, nil, nil) 197 require.NoError(t, err) 198 // When this check fails locally, check your kubeconfig. 199 // context has to reference the default namespace 200 assert.Equal(t, 2, len(assetList)) 201 sort.Slice(assetList, func(i, j int) bool { 202 return assetList[i].Name < assetList[j].Name 203 }) 204 assert.Contains(t, assetList[0].Platform.Family, "k8s-workload") 205 assert.Contains(t, assetList[0].Platform.Family, "k8s") 206 assert.Equal(t, "k8s-manifest", assetList[0].Platform.Runtime) 207 assert.Equal(t, "k8s-pod", assetList[0].Platform.Name) 208 assert.Equal(t, "default/hello-pod-2", assetList[0].Name) 209 assert.Contains(t, assetList[1].Platform.Family, "k8s-workload") 210 assert.Contains(t, assetList[1].Platform.Family, "k8s") 211 assert.Equal(t, "k8s-manifest", assetList[1].Platform.Runtime) 212 assert.Equal(t, "k8s-pod", assetList[1].Platform.Name) 213 assert.Equal(t, "default/mondoo", assetList[1].Name) 214 } 215 216 func TestManifestResolverWrongDiscovery(t *testing.T) { 217 resolver := &Resolver{} 218 manifestFile := "../../providers/k8s/resources/testdata/cronjob.yaml" 219 220 ctx := resources.SetDiscoveryCache(context.Background(), resources.NewDiscoveryCache()) 221 222 assetList, err := resolver.Resolve(ctx, &asset.Asset{}, &providers.Config{ 223 Backend: providers.ProviderType_K8S, 224 Options: map[string]string{ 225 "path": manifestFile, 226 "namespace": "default", 227 }, 228 Discover: &providers.Discovery{ 229 Targets: []string{"pods"}, 230 }, 231 }, nil, nil) 232 require.NoError(t, err) 233 // When this check fails locally, check your kubeconfig. 234 // context has to reference the default namespace 235 assert.Equalf(t, 0, len(assetList), "discovering pods in a cronjob manifest should result in no assets") 236 } 237 238 func TestResourceFilter(t *testing.T) { 239 cfg := &providers.Config{ 240 Backend: providers.ProviderType_K8S, 241 Options: map[string]string{ 242 "k8s-resources": "pod:default:nginx, pod:default:redis, deployment:test:redis, node:node1", 243 }, 244 } 245 246 resFilters, err := resourceFilters(cfg) 247 require.NoError(t, err) 248 249 expected := map[string][]K8sResourceIdentifier{ 250 "pod": { 251 {Type: "pod", Namespace: "default", Name: "nginx"}, 252 {Type: "pod", Namespace: "default", Name: "redis"}, 253 }, 254 "deployment": { 255 {Type: "deployment", Namespace: "test", Name: "redis"}, 256 }, 257 "node": { 258 {Type: "node", Namespace: "", Name: "node1"}, 259 }, 260 } 261 262 assert.Equal(t, expected, resFilters) 263 }