...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/partialpolicy/bindings_test.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/partialpolicy

     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 partialpolicy_test
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"testing"
    21  
    22  	iamv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
    23  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/partialpolicy"
    24  
    25  	"github.com/google/go-cmp/cmp"
    26  )
    27  
    28  // mockIdentityResolver helps to resolve referenced member identity
    29  type mockIdentityResolver struct{}
    30  
    31  func (t *mockIdentityResolver) Resolve(member iamv1beta1.Member, memberFrom *iamv1beta1.MemberSource, defaultNamespace string) (string, error) {
    32  	if member != "" {
    33  		return string(member), nil
    34  	}
    35  
    36  	if memberFrom.ServiceAccountRef != nil {
    37  		if memberFrom.ServiceAccountRef.Namespace == "cnrm-foo" && memberFrom.ServiceAccountRef.Name == "cnrm-sa" {
    38  			return "serviceAccount:foo@domain.com", nil
    39  		}
    40  	}
    41  	panic(fmt.Errorf("memberFrom is not mocked"))
    42  }
    43  
    44  func TestComputePartialPolicyWithMergedBindings(t *testing.T) {
    45  	condition1 := newIAMCondition("test-iam-condition1")
    46  	condition2 := newIAMCondition("test-iam-condition2")
    47  	tests := []struct {
    48  		name          string
    49  		partialPolicy *iamv1beta1.IAMPartialPolicy
    50  		livePolicy    *iamv1beta1.IAMPolicy
    51  		mergedPolicy  *iamv1beta1.IAMPartialPolicy
    52  	}{
    53  		{
    54  			name: "empty partial policy with empty live policy",
    55  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
    56  				Spec: iamv1beta1.IAMPartialPolicySpec{},
    57  			},
    58  			livePolicy: &iamv1beta1.IAMPolicy{
    59  				Spec: iamv1beta1.IAMPolicySpec{},
    60  			},
    61  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
    62  				Spec: iamv1beta1.IAMPartialPolicySpec{},
    63  				Status: iamv1beta1.IAMPartialPolicyStatus{
    64  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
    65  					AllBindings:         []iamv1beta1.IAMPolicyBinding{},
    66  				},
    67  			},
    68  		},
    69  		{
    70  			name: "empty partial policy with non-empty live policy",
    71  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
    72  				Spec: iamv1beta1.IAMPartialPolicySpec{},
    73  			},
    74  			livePolicy: &iamv1beta1.IAMPolicy{
    75  				Spec: iamv1beta1.IAMPolicySpec{
    76  					Bindings: []iamv1beta1.IAMPolicyBinding{
    77  						{
    78  							Role: "roles/owner",
    79  							Members: []iamv1beta1.Member{
    80  								"user:foo@example.com",
    81  								"serviceAccount:foo@domain.com",
    82  							},
    83  						},
    84  					},
    85  				},
    86  			},
    87  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
    88  				Spec: iamv1beta1.IAMPartialPolicySpec{},
    89  				Status: iamv1beta1.IAMPartialPolicyStatus{
    90  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
    91  					AllBindings: []iamv1beta1.IAMPolicyBinding{
    92  						{
    93  							Role: "roles/owner",
    94  							Members: []iamv1beta1.Member{
    95  								"user:foo@example.com",
    96  								"serviceAccount:foo@domain.com",
    97  							},
    98  						},
    99  					},
   100  				},
   101  			},
   102  		},
   103  		{
   104  			name: "no existing bindings from live policy",
   105  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   106  				Spec: iamv1beta1.IAMPartialPolicySpec{
   107  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   108  						{
   109  							Role: "roles/owner",
   110  							Members: []iamv1beta1.IAMPartialPolicyMember{
   111  								{
   112  									Member: "user:foo@example.com",
   113  								},
   114  								{
   115  									Member: "serviceAccount:foo@domain.com",
   116  								},
   117  							},
   118  						},
   119  					},
   120  				},
   121  			},
   122  			livePolicy: &iamv1beta1.IAMPolicy{
   123  				Spec: iamv1beta1.IAMPolicySpec{
   124  					Bindings: []iamv1beta1.IAMPolicyBinding{},
   125  				},
   126  			},
   127  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   128  				Spec: iamv1beta1.IAMPartialPolicySpec{
   129  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   130  						{
   131  							Role: "roles/owner",
   132  							Members: []iamv1beta1.IAMPartialPolicyMember{
   133  								{
   134  									Member: "user:foo@example.com",
   135  								},
   136  								{
   137  									Member: "serviceAccount:foo@domain.com",
   138  								},
   139  							},
   140  						},
   141  					},
   142  				},
   143  				Status: iamv1beta1.IAMPartialPolicyStatus{
   144  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   145  						{
   146  							Role: "roles/owner",
   147  							Members: []iamv1beta1.Member{
   148  								"user:foo@example.com",
   149  								"serviceAccount:foo@domain.com",
   150  							},
   151  						},
   152  					},
   153  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   154  						{
   155  							Role: "roles/owner",
   156  							Members: []iamv1beta1.Member{
   157  								"user:foo@example.com",
   158  								"serviceAccount:foo@domain.com",
   159  							},
   160  						},
   161  					},
   162  				},
   163  			},
   164  		},
   165  		{
   166  			name: "merge bindings with different {role, condition} tuples",
   167  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   168  				Spec: iamv1beta1.IAMPartialPolicySpec{
   169  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   170  						{
   171  							Role: "roles/owner",
   172  							Members: []iamv1beta1.IAMPartialPolicyMember{
   173  								{
   174  									Member: "user:user1@example.com",
   175  								},
   176  								{
   177  									// Resolves to "serviceAccount:foo@domain.com",
   178  									MemberFrom: &iamv1beta1.MemberSource{
   179  										ServiceAccountRef: &iamv1beta1.MemberReference{
   180  											Namespace: "cnrm-foo",
   181  											Name:      "cnrm-sa",
   182  										},
   183  									},
   184  								},
   185  							},
   186  						},
   187  						{
   188  							Role:      "roles/editor",
   189  							Condition: condition1,
   190  							Members: []iamv1beta1.IAMPartialPolicyMember{
   191  								{
   192  									Member: "user:user1@example.com",
   193  								},
   194  							},
   195  						},
   196  					},
   197  				},
   198  			},
   199  			livePolicy: &iamv1beta1.IAMPolicy{
   200  				Spec: iamv1beta1.IAMPolicySpec{
   201  					Bindings: []iamv1beta1.IAMPolicyBinding{
   202  						{
   203  							Role: "roles/editor",
   204  							Members: []iamv1beta1.Member{
   205  								"user:user2@example.com",
   206  							},
   207  						},
   208  					},
   209  				},
   210  			},
   211  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   212  				Spec: iamv1beta1.IAMPartialPolicySpec{
   213  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   214  						{
   215  							Role: "roles/owner",
   216  							Members: []iamv1beta1.IAMPartialPolicyMember{
   217  								{
   218  									Member: "user:user1@example.com",
   219  								},
   220  								{
   221  									// Resolves to "serviceAccount:foo@domain.com",
   222  									MemberFrom: &iamv1beta1.MemberSource{
   223  										ServiceAccountRef: &iamv1beta1.MemberReference{
   224  											Namespace: "cnrm-foo",
   225  											Name:      "cnrm-sa",
   226  										},
   227  									},
   228  								},
   229  							},
   230  						},
   231  						{
   232  							Role:      "roles/editor",
   233  							Condition: condition1,
   234  							Members: []iamv1beta1.IAMPartialPolicyMember{
   235  								{
   236  									Member: "user:user1@example.com",
   237  								},
   238  							},
   239  						},
   240  					},
   241  				},
   242  				Status: iamv1beta1.IAMPartialPolicyStatus{
   243  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   244  						{
   245  							Role:      "roles/editor",
   246  							Condition: condition1,
   247  							Members: []iamv1beta1.Member{
   248  								"user:user1@example.com",
   249  							},
   250  						},
   251  						{
   252  							Role: "roles/owner",
   253  							Members: []iamv1beta1.Member{
   254  								"user:user1@example.com",
   255  								"serviceAccount:foo@domain.com",
   256  							},
   257  						},
   258  					},
   259  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   260  						{
   261  							Role: "roles/editor",
   262  							Members: []iamv1beta1.Member{
   263  								"user:user2@example.com",
   264  							},
   265  						},
   266  						{
   267  							Role:      "roles/editor",
   268  							Condition: condition1,
   269  							Members: []iamv1beta1.Member{
   270  								"user:user1@example.com",
   271  							},
   272  						},
   273  						{
   274  							Role: "roles/owner",
   275  							Members: []iamv1beta1.Member{
   276  								"user:user1@example.com",
   277  								"serviceAccount:foo@domain.com",
   278  							},
   279  						},
   280  					},
   281  				},
   282  			},
   283  		},
   284  		{
   285  			name: "merge members with same {role, condition} tuples",
   286  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   287  				Spec: iamv1beta1.IAMPartialPolicySpec{
   288  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   289  						{
   290  							Role: "roles/editor",
   291  							Members: []iamv1beta1.IAMPartialPolicyMember{
   292  								{
   293  									Member: "user:user1@example.com",
   294  								},
   295  								{
   296  									Member: "serviceAccount:foo@domain.com",
   297  								},
   298  							},
   299  						},
   300  						{
   301  							Role:      "roles/editor",
   302  							Condition: condition1,
   303  							Members: []iamv1beta1.IAMPartialPolicyMember{
   304  								{
   305  									Member: "user:user2@example.com",
   306  								},
   307  							},
   308  						},
   309  					},
   310  				},
   311  			},
   312  			livePolicy: &iamv1beta1.IAMPolicy{
   313  				Spec: iamv1beta1.IAMPolicySpec{
   314  					Bindings: []iamv1beta1.IAMPolicyBinding{
   315  						{
   316  							Role: "roles/editor",
   317  							Members: []iamv1beta1.Member{
   318  								"user:foo@example.com",
   319  							},
   320  						},
   321  						{
   322  							Role:      "roles/editor",
   323  							Condition: condition1,
   324  							Members: []iamv1beta1.Member{
   325  								"user:bar@example.com",
   326  							},
   327  						},
   328  					},
   329  				},
   330  			},
   331  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   332  				Spec: iamv1beta1.IAMPartialPolicySpec{
   333  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   334  						{
   335  							Role: "roles/editor",
   336  							Members: []iamv1beta1.IAMPartialPolicyMember{
   337  								{
   338  									Member: "user:user1@example.com",
   339  								},
   340  								{
   341  									Member: "serviceAccount:foo@domain.com",
   342  								},
   343  							},
   344  						},
   345  						{
   346  							Role:      "roles/editor",
   347  							Condition: condition1,
   348  							Members: []iamv1beta1.IAMPartialPolicyMember{
   349  								{
   350  									Member: "user:user2@example.com",
   351  								},
   352  							},
   353  						},
   354  					},
   355  				},
   356  				Status: iamv1beta1.IAMPartialPolicyStatus{
   357  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   358  						{
   359  							Role: "roles/editor",
   360  							Members: []iamv1beta1.Member{
   361  								"user:user1@example.com",
   362  								"serviceAccount:foo@domain.com",
   363  							},
   364  						},
   365  						{
   366  							Role:      "roles/editor",
   367  							Condition: condition1,
   368  							Members: []iamv1beta1.Member{
   369  								"user:user2@example.com",
   370  							},
   371  						},
   372  					},
   373  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   374  						{
   375  							Role: "roles/editor",
   376  							Members: []iamv1beta1.Member{
   377  								"serviceAccount:foo@domain.com",
   378  								"user:foo@example.com",
   379  								"user:user1@example.com",
   380  							},
   381  						},
   382  						{
   383  							Role:      "roles/editor",
   384  							Condition: condition1,
   385  							Members: []iamv1beta1.Member{
   386  								"user:bar@example.com",
   387  								"user:user2@example.com",
   388  							},
   389  						},
   390  					},
   391  				},
   392  			},
   393  		},
   394  		{
   395  			name: "merge members from multiple entries with same {role, condition} tuples in the same binding slice",
   396  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   397  				Spec: iamv1beta1.IAMPartialPolicySpec{
   398  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   399  						{
   400  							Role:      "roles/editor",
   401  							Condition: condition1,
   402  							Members: []iamv1beta1.IAMPartialPolicyMember{
   403  								{
   404  									Member: "user:user1@example.com",
   405  								},
   406  								{
   407  									Member: "serviceAccount:foo@domain.com",
   408  								},
   409  							},
   410  						},
   411  						{
   412  							Role:      "roles/editor",
   413  							Condition: condition1,
   414  							Members: []iamv1beta1.IAMPartialPolicyMember{
   415  								{
   416  									Member: "user:user3@example.com",
   417  								},
   418  							},
   419  						},
   420  						{
   421  							Role:      "roles/editor",
   422  							Condition: condition1,
   423  							Members: []iamv1beta1.IAMPartialPolicyMember{
   424  								{
   425  									Member: "user:user2@example.com",
   426  								},
   427  							},
   428  						},
   429  						{
   430  							Role:      "roles/editor",
   431  							Condition: condition2,
   432  							Members: []iamv1beta1.IAMPartialPolicyMember{
   433  								{
   434  									Member: "user:user1@example.com",
   435  								},
   436  							},
   437  						},
   438  						{
   439  							Role:      "roles/editor",
   440  							Condition: condition2,
   441  							Members: []iamv1beta1.IAMPartialPolicyMember{
   442  								{
   443  									Member: "user:user2@example.com",
   444  								},
   445  							},
   446  						},
   447  					},
   448  				},
   449  			},
   450  			livePolicy: &iamv1beta1.IAMPolicy{
   451  				Spec: iamv1beta1.IAMPolicySpec{
   452  					Bindings: []iamv1beta1.IAMPolicyBinding{
   453  						{
   454  							Role:      "roles/editor",
   455  							Condition: condition1,
   456  							Members: []iamv1beta1.Member{
   457  								"user:foo@example.com",
   458  							},
   459  						},
   460  						{
   461  							Role:      "roles/editor",
   462  							Condition: condition2,
   463  							Members: []iamv1beta1.Member{
   464  								"user:bar@example.com",
   465  							},
   466  						},
   467  					},
   468  				},
   469  			},
   470  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   471  				Spec: iamv1beta1.IAMPartialPolicySpec{
   472  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   473  						{
   474  							Role:      "roles/editor",
   475  							Condition: condition1,
   476  							Members: []iamv1beta1.IAMPartialPolicyMember{
   477  								{
   478  									Member: "user:user1@example.com",
   479  								},
   480  								{
   481  									Member: "serviceAccount:foo@domain.com",
   482  								},
   483  							},
   484  						},
   485  						{
   486  							Role:      "roles/editor",
   487  							Condition: condition1,
   488  							Members: []iamv1beta1.IAMPartialPolicyMember{
   489  								{
   490  									Member: "user:user3@example.com",
   491  								},
   492  							},
   493  						},
   494  						{
   495  							Role:      "roles/editor",
   496  							Condition: condition1,
   497  							Members: []iamv1beta1.IAMPartialPolicyMember{
   498  								{
   499  									Member: "user:user2@example.com",
   500  								},
   501  							},
   502  						},
   503  						{
   504  							Role:      "roles/editor",
   505  							Condition: condition2,
   506  							Members: []iamv1beta1.IAMPartialPolicyMember{
   507  								{
   508  									Member: "user:user1@example.com",
   509  								},
   510  							},
   511  						},
   512  						{
   513  							Role:      "roles/editor",
   514  							Condition: condition2,
   515  							Members: []iamv1beta1.IAMPartialPolicyMember{
   516  								{
   517  									Member: "user:user2@example.com",
   518  								},
   519  							},
   520  						},
   521  					},
   522  				},
   523  				Status: iamv1beta1.IAMPartialPolicyStatus{
   524  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   525  						{
   526  							Role:      "roles/editor",
   527  							Condition: condition1,
   528  							Members: []iamv1beta1.Member{
   529  								"serviceAccount:foo@domain.com",
   530  								"user:user1@example.com",
   531  								"user:user2@example.com",
   532  								"user:user3@example.com",
   533  							},
   534  						},
   535  						{
   536  							Role:      "roles/editor",
   537  							Condition: condition2,
   538  							Members: []iamv1beta1.Member{
   539  								"user:user1@example.com",
   540  								"user:user2@example.com",
   541  							},
   542  						},
   543  					},
   544  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   545  						{
   546  							Role:      "roles/editor",
   547  							Condition: condition1,
   548  							Members: []iamv1beta1.Member{
   549  								"serviceAccount:foo@domain.com",
   550  								"user:foo@example.com",
   551  								"user:user1@example.com",
   552  								"user:user2@example.com",
   553  								"user:user3@example.com",
   554  							},
   555  						},
   556  						{
   557  							Role:      "roles/editor",
   558  							Condition: condition2,
   559  							Members: []iamv1beta1.Member{
   560  								"user:bar@example.com",
   561  								"user:user1@example.com",
   562  								"user:user2@example.com",
   563  							},
   564  						},
   565  					},
   566  				},
   567  			},
   568  		},
   569  		{
   570  			name: "empty member arrays",
   571  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   572  				Spec: iamv1beta1.IAMPartialPolicySpec{
   573  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   574  						{
   575  							Role: "roles/owner",
   576  							Members: []iamv1beta1.IAMPartialPolicyMember{
   577  								{
   578  									Member: "user:foo@example.com",
   579  								},
   580  								{
   581  									Member: "serviceAccount:foo@domain.com",
   582  								},
   583  							},
   584  						},
   585  						{
   586  							Role:    "roles/viewer",
   587  							Members: []iamv1beta1.IAMPartialPolicyMember{},
   588  						},
   589  					},
   590  				},
   591  			},
   592  			livePolicy: &iamv1beta1.IAMPolicy{
   593  				Spec: iamv1beta1.IAMPolicySpec{
   594  					Bindings: []iamv1beta1.IAMPolicyBinding{},
   595  				},
   596  			},
   597  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   598  				Spec: iamv1beta1.IAMPartialPolicySpec{
   599  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   600  						{
   601  							Role: "roles/owner",
   602  							Members: []iamv1beta1.IAMPartialPolicyMember{
   603  								{
   604  									Member: "user:foo@example.com",
   605  								},
   606  								{
   607  									Member: "serviceAccount:foo@domain.com",
   608  								},
   609  							},
   610  						},
   611  						{
   612  							Role:    "roles/viewer",
   613  							Members: []iamv1beta1.IAMPartialPolicyMember{},
   614  						},
   615  					},
   616  				},
   617  				Status: iamv1beta1.IAMPartialPolicyStatus{
   618  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   619  						{
   620  							Role: "roles/owner",
   621  							Members: []iamv1beta1.Member{
   622  								"user:foo@example.com",
   623  								"serviceAccount:foo@domain.com",
   624  							},
   625  						},
   626  					},
   627  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   628  						{
   629  							Role: "roles/owner",
   630  							Members: []iamv1beta1.Member{
   631  								"user:foo@example.com",
   632  								"serviceAccount:foo@domain.com",
   633  							},
   634  						},
   635  					},
   636  				},
   637  			},
   638  		},
   639  		{
   640  			name: "remove partial managed bindings from spec compared to lastAppliedBindings",
   641  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   642  				Spec: iamv1beta1.IAMPartialPolicySpec{
   643  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   644  						{
   645  							Role: "roles/editor",
   646  							Members: []iamv1beta1.IAMPartialPolicyMember{
   647  								{
   648  									Member: "user:foo@example.com",
   649  								},
   650  							},
   651  						},
   652  					},
   653  				},
   654  				Status: iamv1beta1.IAMPartialPolicyStatus{
   655  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   656  						{
   657  							Role: "roles/editor",
   658  							Members: []iamv1beta1.Member{
   659  								"user:foo@example.com",
   660  								"serviceAccount:foo@domain.com",
   661  							},
   662  						},
   663  						{
   664  							Role:      "roles/editor",
   665  							Condition: condition1,
   666  							Members: []iamv1beta1.Member{
   667  								"user:bar@example.com",
   668  							},
   669  						},
   670  						{
   671  							Role: "roles/owner",
   672  							Members: []iamv1beta1.Member{
   673  								"user:user1@example.com",
   674  								"serviceAccount:foo@domain.com",
   675  							},
   676  						},
   677  					},
   678  				},
   679  			},
   680  			livePolicy: &iamv1beta1.IAMPolicy{
   681  				Spec: iamv1beta1.IAMPolicySpec{
   682  					Bindings: []iamv1beta1.IAMPolicyBinding{
   683  						{
   684  							Role: "roles/editor",
   685  							Members: []iamv1beta1.Member{
   686  								"user:foo@example.com",
   687  								"serviceAccount:foo@domain.com",
   688  							},
   689  						},
   690  						{
   691  							Role:      "roles/editor",
   692  							Condition: condition1,
   693  							Members: []iamv1beta1.Member{
   694  								"user:bar@example.com",
   695  								"user:user1@example.com",
   696  							},
   697  						},
   698  						{
   699  							Role: "roles/owner",
   700  							Members: []iamv1beta1.Member{
   701  								"user:user1@example.com",
   702  								"serviceAccount:foo@domain.com",
   703  							},
   704  						},
   705  					},
   706  				},
   707  			},
   708  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   709  				Spec: iamv1beta1.IAMPartialPolicySpec{
   710  					Bindings: []iamv1beta1.IAMPartialPolicyBinding{
   711  						{
   712  							Role: "roles/editor",
   713  							Members: []iamv1beta1.IAMPartialPolicyMember{
   714  								{
   715  									Member: "user:foo@example.com",
   716  								},
   717  							},
   718  						},
   719  					},
   720  				},
   721  				Status: iamv1beta1.IAMPartialPolicyStatus{
   722  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   723  						{
   724  							Role: "roles/editor",
   725  							Members: []iamv1beta1.Member{
   726  								"user:foo@example.com",
   727  							},
   728  						},
   729  					},
   730  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   731  						{
   732  							Role: "roles/editor",
   733  							Members: []iamv1beta1.Member{
   734  								"user:foo@example.com",
   735  							},
   736  						},
   737  						{
   738  							Role:      "roles/editor",
   739  							Condition: condition1,
   740  							Members: []iamv1beta1.Member{
   741  								"user:user1@example.com",
   742  							},
   743  						},
   744  					},
   745  				},
   746  			},
   747  		},
   748  		{
   749  			name: "remove all managed bindings from spec compared to lastAppliedBindings",
   750  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   751  				Spec: iamv1beta1.IAMPartialPolicySpec{},
   752  				Status: iamv1beta1.IAMPartialPolicyStatus{
   753  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   754  						{
   755  							Role: "roles/editor",
   756  							Members: []iamv1beta1.Member{
   757  								"user:foo@example.com",
   758  								"serviceAccount:foo@domain.com",
   759  							},
   760  						},
   761  						{
   762  							Role:      "roles/editor",
   763  							Condition: condition1,
   764  							Members: []iamv1beta1.Member{
   765  								"user:bar@example.com",
   766  							},
   767  						},
   768  						{
   769  							Role: "roles/viewer",
   770  							Members: []iamv1beta1.Member{
   771  								"user:foo@example.com",
   772  							},
   773  						},
   774  					},
   775  				},
   776  			},
   777  			livePolicy: &iamv1beta1.IAMPolicy{
   778  				Spec: iamv1beta1.IAMPolicySpec{
   779  					Bindings: []iamv1beta1.IAMPolicyBinding{
   780  						{
   781  							Role: "roles/editor",
   782  							Members: []iamv1beta1.Member{
   783  								"user:foo@example.com",
   784  								"serviceAccount:foo@domain.com",
   785  							},
   786  						},
   787  						{
   788  							Role:      "roles/editor",
   789  							Condition: condition1,
   790  							Members: []iamv1beta1.Member{
   791  								"user:bar@example.com",
   792  								"user:user1@example.com",
   793  							},
   794  						},
   795  						{
   796  							Role: "roles/owner",
   797  							Members: []iamv1beta1.Member{
   798  								"user:bar@example.com",
   799  							},
   800  						},
   801  					},
   802  				},
   803  			},
   804  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   805  				Spec: iamv1beta1.IAMPartialPolicySpec{},
   806  				Status: iamv1beta1.IAMPartialPolicyStatus{
   807  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
   808  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   809  						{
   810  							Role:      "roles/editor",
   811  							Condition: condition1,
   812  							Members: []iamv1beta1.Member{
   813  								"user:user1@example.com",
   814  							},
   815  						},
   816  						{
   817  							Role: "roles/owner",
   818  							Members: []iamv1beta1.Member{
   819  								"user:bar@example.com",
   820  							},
   821  						},
   822  					},
   823  				},
   824  			},
   825  		},
   826  		{
   827  			name: "remove all bindings",
   828  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   829  				Spec: iamv1beta1.IAMPartialPolicySpec{},
   830  				Status: iamv1beta1.IAMPartialPolicyStatus{
   831  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   832  						{
   833  							Role: "roles/editor",
   834  							Members: []iamv1beta1.Member{
   835  								"user:foo@example.com",
   836  								"serviceAccount:foo@domain.com",
   837  							},
   838  						},
   839  						{
   840  							Role:      "roles/editor",
   841  							Condition: condition1,
   842  							Members: []iamv1beta1.Member{
   843  								"user:bar@example.com",
   844  							},
   845  						},
   846  					},
   847  				},
   848  			},
   849  			livePolicy: &iamv1beta1.IAMPolicy{
   850  				Spec: iamv1beta1.IAMPolicySpec{
   851  					Bindings: []iamv1beta1.IAMPolicyBinding{
   852  						{
   853  							Role: "roles/editor",
   854  							Members: []iamv1beta1.Member{
   855  								"user:foo@example.com",
   856  								"serviceAccount:foo@domain.com",
   857  							},
   858  						},
   859  						{
   860  							Role:      "roles/editor",
   861  							Condition: condition1,
   862  							Members: []iamv1beta1.Member{
   863  								"user:bar@example.com",
   864  							},
   865  						},
   866  					},
   867  				},
   868  			},
   869  			mergedPolicy: &iamv1beta1.IAMPartialPolicy{
   870  				Spec: iamv1beta1.IAMPartialPolicySpec{},
   871  				Status: iamv1beta1.IAMPartialPolicyStatus{
   872  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
   873  					AllBindings:         []iamv1beta1.IAMPolicyBinding{},
   874  				},
   875  			},
   876  		},
   877  	}
   878  	for _, tc := range tests {
   879  		tc := tc
   880  		t.Run(tc.name, func(t *testing.T) {
   881  			t.Parallel()
   882  			resolver := mockIdentityResolver{}
   883  			res, err := partialpolicy.ComputePartialPolicyWithMergedBindings(tc.partialPolicy, tc.livePolicy, &resolver)
   884  			if err != nil {
   885  				t.Fatalf("error when computing partial policy with merged bindings: %v", err)
   886  			}
   887  			if !reflect.DeepEqual(res, tc.mergedPolicy) {
   888  				t.Fatalf("unexpected merged policy diff (-want +got): \n%v", cmp.Diff(tc.mergedPolicy, res))
   889  			}
   890  		})
   891  	}
   892  }
   893  
   894  func TestComputePartialPolicyWithRemainingBindings(t *testing.T) {
   895  	condition1 := newIAMCondition("test-iam-condition1")
   896  	tests := []struct {
   897  		name          string
   898  		partialPolicy *iamv1beta1.IAMPartialPolicy
   899  		livePolicy    *iamv1beta1.IAMPolicy
   900  		remaining     *iamv1beta1.IAMPartialPolicy
   901  	}{
   902  		{
   903  			name: "remove previously managed bindings",
   904  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   905  				Status: iamv1beta1.IAMPartialPolicyStatus{
   906  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
   907  						{
   908  							Role:      "roles/editor",
   909  							Condition: condition1,
   910  							Members: []iamv1beta1.Member{
   911  								"user:user1@example.com",
   912  							},
   913  						},
   914  						{
   915  							Role: "roles/owner",
   916  							Members: []iamv1beta1.Member{
   917  								"user:user1@example.com",
   918  							},
   919  						},
   920  					},
   921  				},
   922  			},
   923  			livePolicy: &iamv1beta1.IAMPolicy{
   924  				Spec: iamv1beta1.IAMPolicySpec{
   925  					Bindings: []iamv1beta1.IAMPolicyBinding{
   926  						{
   927  							Role: "roles/editor",
   928  							Members: []iamv1beta1.Member{
   929  								"user:user2@example.com",
   930  							},
   931  						},
   932  						{
   933  							Role:      "roles/editor",
   934  							Condition: condition1,
   935  							Members: []iamv1beta1.Member{
   936  								"user:user1@example.com",
   937  							},
   938  						},
   939  						{
   940  							Role: "roles/owner",
   941  							Members: []iamv1beta1.Member{
   942  								"user:user1@example.com",
   943  								"serviceAccount:foo@domain.com",
   944  							},
   945  						},
   946  					},
   947  				},
   948  			},
   949  			remaining: &iamv1beta1.IAMPartialPolicy{
   950  				Status: iamv1beta1.IAMPartialPolicyStatus{
   951  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
   952  					AllBindings: []iamv1beta1.IAMPolicyBinding{
   953  						{
   954  							Role: "roles/editor",
   955  							Members: []iamv1beta1.Member{
   956  								"user:user2@example.com",
   957  							},
   958  						},
   959  						{
   960  							Role: "roles/owner",
   961  							Members: []iamv1beta1.Member{
   962  								"serviceAccount:foo@domain.com",
   963  							},
   964  						},
   965  					},
   966  				},
   967  			},
   968  		},
   969  		{
   970  			name: "no previously managed bindings to remove",
   971  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
   972  				Status: iamv1beta1.IAMPartialPolicyStatus{
   973  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
   974  				},
   975  			},
   976  			livePolicy: &iamv1beta1.IAMPolicy{
   977  				Spec: iamv1beta1.IAMPolicySpec{
   978  					Bindings: []iamv1beta1.IAMPolicyBinding{
   979  						{
   980  							Role: "roles/editor",
   981  							Members: []iamv1beta1.Member{
   982  								"user:user2@example.com",
   983  							},
   984  						},
   985  						{
   986  							Role:      "roles/editor",
   987  							Condition: condition1,
   988  							Members: []iamv1beta1.Member{
   989  								"user:user1@example.com",
   990  							},
   991  						},
   992  						{
   993  							Role: "roles/owner",
   994  							Members: []iamv1beta1.Member{
   995  								"user:user1@example.com",
   996  								"serviceAccount:foo@domain.com",
   997  							},
   998  						},
   999  					},
  1000  				},
  1001  			},
  1002  			remaining: &iamv1beta1.IAMPartialPolicy{
  1003  				Status: iamv1beta1.IAMPartialPolicyStatus{
  1004  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
  1005  					AllBindings: []iamv1beta1.IAMPolicyBinding{
  1006  						{
  1007  							Role: "roles/editor",
  1008  							Members: []iamv1beta1.Member{
  1009  								"user:user2@example.com",
  1010  							},
  1011  						},
  1012  						{
  1013  							Role:      "roles/editor",
  1014  							Condition: condition1,
  1015  							Members: []iamv1beta1.Member{
  1016  								"user:user1@example.com",
  1017  							},
  1018  						},
  1019  						{
  1020  							Role: "roles/owner",
  1021  							Members: []iamv1beta1.Member{
  1022  								"user:user1@example.com",
  1023  								"serviceAccount:foo@domain.com",
  1024  							},
  1025  						},
  1026  					},
  1027  				},
  1028  			},
  1029  		},
  1030  		{
  1031  			name: "all bindings are removed",
  1032  			partialPolicy: &iamv1beta1.IAMPartialPolicy{
  1033  				Status: iamv1beta1.IAMPartialPolicyStatus{
  1034  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{
  1035  						{
  1036  							Role:      "roles/editor",
  1037  							Condition: condition1,
  1038  							Members: []iamv1beta1.Member{
  1039  								"user:user1@example.com",
  1040  							},
  1041  						},
  1042  						{
  1043  							Role: "roles/editor",
  1044  							Members: []iamv1beta1.Member{
  1045  								"user:user2@example.com",
  1046  							},
  1047  						},
  1048  						{
  1049  							Role: "roles/owner",
  1050  							Members: []iamv1beta1.Member{
  1051  								"user:user1@example.com",
  1052  							},
  1053  						},
  1054  						// roles that are removed out of band
  1055  						// and KCC hasn't drift-corrected yet before deletion.
  1056  						{
  1057  							Role: "roles/viewer",
  1058  							Members: []iamv1beta1.Member{
  1059  								"user:user2@example.com",
  1060  							},
  1061  						},
  1062  					},
  1063  				},
  1064  			},
  1065  			livePolicy: &iamv1beta1.IAMPolicy{
  1066  				Spec: iamv1beta1.IAMPolicySpec{
  1067  					Bindings: []iamv1beta1.IAMPolicyBinding{
  1068  						{
  1069  							Role: "roles/editor",
  1070  							Members: []iamv1beta1.Member{
  1071  								"user:user2@example.com",
  1072  							},
  1073  						},
  1074  						{
  1075  							Role:      "roles/editor",
  1076  							Condition: condition1,
  1077  							Members: []iamv1beta1.Member{
  1078  								"user:user1@example.com",
  1079  							},
  1080  						},
  1081  						{
  1082  							Role: "roles/owner",
  1083  							Members: []iamv1beta1.Member{
  1084  								"user:user1@example.com",
  1085  							},
  1086  						},
  1087  					},
  1088  				},
  1089  			},
  1090  			remaining: &iamv1beta1.IAMPartialPolicy{
  1091  				Status: iamv1beta1.IAMPartialPolicyStatus{
  1092  					LastAppliedBindings: []iamv1beta1.IAMPolicyBinding{},
  1093  					AllBindings:         []iamv1beta1.IAMPolicyBinding{},
  1094  				},
  1095  			},
  1096  		},
  1097  	}
  1098  	for _, tc := range tests {
  1099  		tc := tc
  1100  		t.Run(tc.name, func(t *testing.T) {
  1101  			t.Parallel()
  1102  			res := partialpolicy.ComputePartialPolicyWithRemainingBindings(tc.partialPolicy, tc.livePolicy)
  1103  			if !reflect.DeepEqual(res, tc.remaining) {
  1104  				t.Fatalf("unexpected merged policy diff (-want +got): \n%v", cmp.Diff(tc.remaining, res))
  1105  			}
  1106  		})
  1107  	}
  1108  }
  1109  
  1110  func newIAMCondition(title string) *iamv1beta1.IAMCondition {
  1111  	return &iamv1beta1.IAMCondition{
  1112  		Title:       title,
  1113  		Description: "Test IAM Condition",
  1114  		Expression:  "request.time < timestamp(\"2020-01-01T00:00:00Z\")",
  1115  	}
  1116  }
  1117  

View as plain text