...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook/iam_defaulter_test.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/webhook

     1  // Copyright 2022 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package webhook
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  
    21  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
    22  	dclmetadata "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/metadata"
    23  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/deepcopy"
    24  	testutil "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test"
    25  	testservicemappingloader "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/servicemappingloader"
    26  
    27  	"github.com/google/go-cmp/cmp"
    28  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    29  )
    30  
    31  func TestDefaultAPIVersionForIAMResourceRef(t *testing.T) {
    32  	tests := []struct {
    33  		name           string
    34  		resourceRef    map[string]interface{}
    35  		resourceRefNew map[string]interface{}
    36  		denied         bool
    37  	}{
    38  		{
    39  			name:   "spec.resourceRef is not set",
    40  			denied: true,
    41  		},
    42  		{
    43  			name: "spec.resourceRef.kind is not set",
    44  			resourceRef: map[string]interface{}{
    45  				"name": "resource-name",
    46  			},
    47  			denied: true,
    48  		},
    49  		{
    50  			name: "spec.resourceRef.kind is set to unsupported kind",
    51  			resourceRef: map[string]interface{}{
    52  				"kind": "UnsupportedKind",
    53  				"name": "resource-name",
    54  			},
    55  			denied: true,
    56  		},
    57  		{
    58  			name: "spec.resourceRef.apiVersion is already set",
    59  			resourceRef: map[string]interface{}{
    60  				"apiVersion": "pubsub.cnrm.cloud.google.com/v1beta1",
    61  				"kind":       "PubSubTopic",
    62  				"name":       "resource-name",
    63  			},
    64  			resourceRefNew: map[string]interface{}{
    65  				"apiVersion": "pubsub.cnrm.cloud.google.com/v1beta1",
    66  				"kind":       "PubSubTopic",
    67  				"name":       "resource-name",
    68  			},
    69  		},
    70  		{
    71  			name: "spec.resourceRef.apiVersion is not set",
    72  			resourceRef: map[string]interface{}{
    73  				"kind": "PubSubTopic",
    74  				"name": "resource-name",
    75  			},
    76  			resourceRefNew: map[string]interface{}{
    77  				"apiVersion": "pubsub.cnrm.cloud.google.com/v1beta1",
    78  				"kind":       "PubSubTopic",
    79  				"name":       "resource-name",
    80  			},
    81  		},
    82  		{
    83  			name: "spec.resourceRef.apiVersion is not set, and spec.resourceRef.kind is set to an external-only kind Organization",
    84  			resourceRef: map[string]interface{}{
    85  				"kind": "Organization",
    86  				"name": "resource-name",
    87  			},
    88  			resourceRefNew: map[string]interface{}{
    89  				"apiVersion": "resourcemanager.cnrm.cloud.google.com/v1beta1",
    90  				"kind":       "Organization",
    91  				"name":       "resource-name",
    92  			},
    93  		},
    94  		{
    95  			name: "spec.resourceRef.apiVersion is not set, and spec.resourceRef.kind is set to an external-only kind BillingAccount",
    96  			resourceRef: map[string]interface{}{
    97  				"kind": "BillingAccount",
    98  				"name": "resource-name",
    99  			},
   100  			resourceRefNew: map[string]interface{}{
   101  				"apiVersion": "billing.cnrm.cloud.google.com/v1beta1",
   102  				"kind":       "BillingAccount",
   103  				"name":       "resource-name",
   104  			},
   105  		},
   106  	}
   107  
   108  	iamTemplates := map[string]map[string]interface{}{
   109  		"IAMPolicy": map[string]interface{}{
   110  			"apiVersion": v1beta1.IAMPolicyGVK.GroupVersion().String(),
   111  			"kind":       v1beta1.IAMPolicyGVK.Kind,
   112  			"metadata": map[string]interface{}{
   113  				"name": "policy",
   114  			},
   115  			"spec": map[string]interface{}{
   116  				"bindings": []interface{}{
   117  					map[string]interface{}{
   118  						"role": "role",
   119  						"members": []interface{}{
   120  							"member",
   121  						},
   122  					},
   123  				},
   124  			},
   125  		},
   126  		"IAMPartialPolicy": map[string]interface{}{
   127  			"apiVersion": v1beta1.IAMPartialPolicyGVK.GroupVersion().String(),
   128  			"kind":       v1beta1.IAMPartialPolicyGVK.Kind,
   129  			"metadata": map[string]interface{}{
   130  				"name": "policy",
   131  			},
   132  			"spec": map[string]interface{}{
   133  				"bindings": []interface{}{
   134  					map[string]interface{}{
   135  						"role": "role",
   136  						"members": []interface{}{
   137  							map[string]interface{}{
   138  								"member": "member",
   139  							},
   140  						},
   141  					},
   142  				},
   143  			},
   144  		},
   145  		"IAMPolicyMember": map[string]interface{}{
   146  			"apiVersion": v1beta1.IAMPolicyMemberGVK.GroupVersion().String(),
   147  			"kind":       v1beta1.IAMPolicyMemberGVK.Kind,
   148  			"metadata": map[string]interface{}{
   149  				"name": "policy",
   150  			},
   151  			"spec": map[string]interface{}{
   152  				"member": "member",
   153  				"role":   "role",
   154  			},
   155  		},
   156  		"IAMAuditConfig": map[string]interface{}{
   157  			"apiVersion": v1beta1.IAMAuditConfigGVK.GroupVersion().String(),
   158  			"kind":       v1beta1.IAMAuditConfigGVK.Kind,
   159  			"metadata": map[string]interface{}{
   160  				"name": "policy",
   161  			},
   162  			"spec": map[string]interface{}{
   163  				"service": "service",
   164  				"auditLogConfigs": []interface{}{
   165  					map[string]interface{}{
   166  						"logType": "log-type",
   167  						"exemptedMembers": []interface{}{
   168  							"member",
   169  						},
   170  					},
   171  				},
   172  			},
   173  		},
   174  	}
   175  
   176  	for iamKind, iamTemplate := range iamTemplates {
   177  		for _, tc := range tests {
   178  			iamKind := iamKind
   179  			iamTemplate := iamTemplate
   180  			tc := tc
   181  			t.Run(fmt.Sprintf("%v (%v)", tc.name, iamKind), func(t *testing.T) {
   182  				t.Parallel()
   183  
   184  				// Create IAM resource to pass into webhook
   185  				iamObj := &unstructured.Unstructured{
   186  					Object: deepcopy.MapStringInterface(iamTemplate),
   187  				}
   188  				if tc.resourceRef != nil {
   189  					if err := unstructured.SetNestedField(iamObj.Object, tc.resourceRef, iamResourceRefPath...); err != nil {
   190  						t.Fatalf("error setting '%v' on IAM resource meant to be passed into webhook: %v", iamResourceRefField, err)
   191  					}
   192  				}
   193  
   194  				// Create IAM resource that we expect the webhook to return
   195  				iamObjExpected := &unstructured.Unstructured{
   196  					Object: deepcopy.MapStringInterface(iamTemplate),
   197  				}
   198  				if tc.resourceRefNew != nil {
   199  					if err := unstructured.SetNestedField(iamObjExpected.Object, tc.resourceRefNew, iamResourceRefPath...); err != nil {
   200  						t.Fatalf("error setting '%v' on IAM resource meant for testing webhook response: %v", iamResourceRefField, err)
   201  					}
   202  				}
   203  
   204  				response := defaultAPIVersionForIAMResourceRef(iamObj, testservicemappingloader.New(t), dclmetadata.New())
   205  				if tc.denied {
   206  					if response.Allowed {
   207  						t.Fatalf("expected request to be denied, but was allowed. Response:\n%v", response)
   208  					}
   209  					return
   210  				}
   211  				if !response.Allowed {
   212  					t.Fatalf("request was unexpectedly denied. Response:\n%v", response)
   213  				}
   214  				expectedResponse := constructPatchResponse(iamObj, iamObjExpected)
   215  				if !testutil.Equals(t, response, expectedResponse) {
   216  					diff := cmp.Diff(expectedResponse, response)
   217  					t.Fatalf("unexpected diff in the response (-want +got):\n%v", diff)
   218  				}
   219  			})
   220  		}
   221  	}
   222  }
   223  

View as plain text