github.com/nginxinc/kubernetes-ingress@v1.12.5/internal/k8s/appprotect/app_protect_configuration_test.go (about)

     1  package appprotect
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    10  )
    11  
    12  func parseTime(value string) *time.Time {
    13  	t, err := time.Parse(timeLayout, value)
    14  	if err != nil {
    15  		panic(err)
    16  	}
    17  
    18  	return &t
    19  }
    20  
    21  func sliceCmpFunc(x, y *unstructured.Unstructured) bool {
    22  	return x.GetUID() > y.GetUID()
    23  }
    24  
    25  var unstructuredSliceCmpOpts = cmpopts.SortSlices(sliceCmpFunc)
    26  
    27  func TestCreateAppProtectPolicyEx(t *testing.T) {
    28  	tests := []struct {
    29  		policy           *unstructured.Unstructured
    30  		expectedPolicyEx *PolicyEx
    31  		wantErr          bool
    32  		msg              string
    33  	}{
    34  		{
    35  			policy: &unstructured.Unstructured{
    36  				Object: map[string]interface{}{
    37  					"metadata": map[string]interface{}{
    38  						"uid": "1",
    39  					},
    40  					"spec": map[string]interface{}{
    41  						"policy": map[string]interface{}{
    42  							"name": "TestPolicy",
    43  							"signature-requirements": []interface{}{
    44  								map[string]interface{}{
    45  									"maxRevisionDatetime": "2020-01-23T18:32:02Z",
    46  									"minRevisionDatetime": "2020-01-21T18:32:02Z",
    47  									"tag":                 "MinMax",
    48  								},
    49  								map[string]interface{}{
    50  									"maxRevisionDatetime": "2020-01-23T18:32:02Z",
    51  									"tag":                 "Max",
    52  								},
    53  								map[string]interface{}{
    54  									"minRevisionDatetime": "2020-01-23T18:32:02Z",
    55  									"tag":                 "Min",
    56  								},
    57  							},
    58  						},
    59  					},
    60  				},
    61  			},
    62  			expectedPolicyEx: &PolicyEx{
    63  				SignatureReqs: []SignatureReq{
    64  					{
    65  						Tag: "MinMax",
    66  						RevTimes: &RevTimes{
    67  							MinRevTime: parseTime("2020-01-21T18:32:02Z"),
    68  							MaxRevTime: parseTime("2020-01-23T18:32:02Z"),
    69  						},
    70  					},
    71  					{
    72  						Tag: "Max",
    73  						RevTimes: &RevTimes{
    74  							MaxRevTime: parseTime("2020-01-23T18:32:02Z"),
    75  						},
    76  					},
    77  					{
    78  						Tag: "Min",
    79  						RevTimes: &RevTimes{
    80  							MinRevTime: parseTime("2020-01-23T18:32:02Z"),
    81  						},
    82  					},
    83  				},
    84  				IsValid:  true,
    85  				ErrorMsg: "",
    86  			},
    87  			wantErr: false,
    88  			msg:     "valid policy",
    89  		},
    90  		{
    91  			policy: &unstructured.Unstructured{
    92  				Object: map[string]interface{}{
    93  					"spec": map[string]interface{}{
    94  						"policy": map[string]interface{}{
    95  							"name": "TestPolicy",
    96  							"signature-requirements": []interface{}{
    97  								map[string]interface{}{
    98  									"minRevisionDatetime": "time",
    99  									"tag":                 "MinMax",
   100  								},
   101  							},
   102  						},
   103  					},
   104  				},
   105  			},
   106  			expectedPolicyEx: &PolicyEx{
   107  				SignatureReqs: nil,
   108  				IsValid:       false,
   109  				ErrorMsg:      "Invalid timestamp",
   110  			},
   111  			wantErr: true,
   112  			msg:     "policy with invalid min timestamp",
   113  		},
   114  		{
   115  			policy: &unstructured.Unstructured{
   116  				Object: map[string]interface{}{
   117  					"spec": map[string]interface{}{
   118  						"policy": map[string]interface{}{
   119  							"name": "TestPolicy",
   120  							"signature-requirements": []interface{}{
   121  								map[string]interface{}{
   122  									"maxRevisionDatetime": "time",
   123  									"tag":                 "MinMax",
   124  								},
   125  							},
   126  						},
   127  					},
   128  				},
   129  			},
   130  			expectedPolicyEx: &PolicyEx{
   131  				SignatureReqs: nil,
   132  				IsValid:       false,
   133  				ErrorMsg:      "Invalid timestamp",
   134  			},
   135  			wantErr: true,
   136  			msg:     "policy with invalid max timestamp",
   137  		},
   138  		{
   139  			policy: &unstructured.Unstructured{
   140  				Object: map[string]interface{}{
   141  					"spec": map[string]interface{}{},
   142  				},
   143  			},
   144  			expectedPolicyEx: &PolicyEx{
   145  				SignatureReqs: nil,
   146  				IsValid:       false,
   147  				ErrorMsg:      "Validation Failed",
   148  			},
   149  			wantErr: true,
   150  			msg:     "policy empty spec",
   151  		},
   152  		{
   153  			policy: &unstructured.Unstructured{
   154  				Object: map[string]interface{}{
   155  					"spec": map[string]interface{}{
   156  						"policy": map[string]interface{}{
   157  							"name": "TestPolicy",
   158  							"signature-requirements": map[string]interface{}{
   159  								"invalid": map[string]interface{}{
   160  									"maxRevisionDatetime": "time",
   161  									"tag":                 "MinMax",
   162  								},
   163  							},
   164  						},
   165  					},
   166  				},
   167  			},
   168  			expectedPolicyEx: &PolicyEx{
   169  				SignatureReqs: nil,
   170  				IsValid:       false,
   171  				ErrorMsg:      failedValidationErrorMsg,
   172  			},
   173  			wantErr: true,
   174  			msg:     "policy with incorrect structure",
   175  		},
   176  	}
   177  
   178  	for _, test := range tests {
   179  		test.expectedPolicyEx.Obj = test.policy
   180  
   181  		policyEx, err := createAppProtectPolicyEx(test.policy)
   182  		if (err != nil) != test.wantErr {
   183  			t.Errorf("createAppProtectPolicyEx() returned %v, for the case of %s", err, test.msg)
   184  		}
   185  		if diff := cmp.Diff(test.expectedPolicyEx, policyEx); diff != "" {
   186  			t.Errorf("createAppProtectPolicyEx() %q returned unexpected result (-want +got):\n%s", test.msg, diff)
   187  		}
   188  	}
   189  }
   190  
   191  func TestCreateAppProtectLogConfEx(t *testing.T) {
   192  	tests := []struct {
   193  		logConf           *unstructured.Unstructured
   194  		expectedLogConfEx *LogConfEx
   195  		wantErr           bool
   196  		msg               string
   197  	}{
   198  		{
   199  			logConf: &unstructured.Unstructured{
   200  				Object: map[string]interface{}{
   201  					"spec": map[string]interface{}{
   202  						"content": map[string]interface{}{},
   203  						"filter":  map[string]interface{}{},
   204  					},
   205  				},
   206  			},
   207  			expectedLogConfEx: &LogConfEx{
   208  				IsValid:  true,
   209  				ErrorMsg: "",
   210  			},
   211  			wantErr: false,
   212  			msg:     "Valid LogConf",
   213  		},
   214  		{
   215  			logConf: &unstructured.Unstructured{
   216  				Object: map[string]interface{}{
   217  					"spec": map[string]interface{}{
   218  						"content": map[string]interface{}{},
   219  					},
   220  				},
   221  			},
   222  			expectedLogConfEx: &LogConfEx{
   223  				IsValid:  false,
   224  				ErrorMsg: failedValidationErrorMsg,
   225  			},
   226  			wantErr: true,
   227  			msg:     "Invalid LogConf",
   228  		},
   229  	}
   230  
   231  	for _, test := range tests {
   232  		test.expectedLogConfEx.Obj = test.logConf
   233  
   234  		policyEx, err := createAppProtectLogConfEx(test.logConf)
   235  		if (err != nil) != test.wantErr {
   236  			t.Errorf("createAppProtectLogConfEx() returned %v, for the case of %s", err, test.msg)
   237  		}
   238  		if diff := cmp.Diff(test.expectedLogConfEx, policyEx); diff != "" {
   239  			t.Errorf("createAppProtectLogConfEx() %q returned unexpected result (-want +got):\n%s", test.msg, diff)
   240  		}
   241  	}
   242  }
   243  
   244  func TestCreateAppProtectUserSigEx(t *testing.T) {
   245  	tests := []struct {
   246  		userSig           *unstructured.Unstructured
   247  		expectedUserSigEx *UserSigEx
   248  		wantErr           bool
   249  		msg               string
   250  	}{
   251  		{
   252  			userSig: &unstructured.Unstructured{
   253  				Object: map[string]interface{}{
   254  					"spec": map[string]interface{}{
   255  						"revisionDatetime": "2020-01-23T18:32:02Z",
   256  						"signatures": []interface{}{
   257  							map[string]interface{}{},
   258  						},
   259  						"tag": "test",
   260  					},
   261  				},
   262  			},
   263  			expectedUserSigEx: &UserSigEx{
   264  				RevTime:  parseTime("2020-01-23T18:32:02Z"),
   265  				IsValid:  true,
   266  				ErrorMsg: "",
   267  				Tag:      "test",
   268  			},
   269  			wantErr: false,
   270  			msg:     "Valid UserSig",
   271  		},
   272  		{
   273  			userSig: &unstructured.Unstructured{
   274  				Object: map[string]interface{}{
   275  					"spec": map[string]interface{}{
   276  						"signatures": []interface{}{
   277  							map[string]interface{}{},
   278  						},
   279  						"tag": "test",
   280  					},
   281  				},
   282  			},
   283  			expectedUserSigEx: &UserSigEx{
   284  				IsValid:  true,
   285  				ErrorMsg: "",
   286  				Tag:      "test",
   287  			},
   288  			wantErr: false,
   289  			msg:     "Valid UserSig, no revDateTime",
   290  		},
   291  		{
   292  			userSig: &unstructured.Unstructured{
   293  				Object: map[string]interface{}{
   294  					"spec": map[string]interface{}{
   295  						"revisionDatetime": "time",
   296  						"signatures": []interface{}{
   297  							map[string]interface{}{},
   298  						},
   299  						"tag": "test",
   300  					},
   301  				},
   302  			},
   303  			expectedUserSigEx: &UserSigEx{
   304  				IsValid:  false,
   305  				ErrorMsg: invalidTimestampErrorMsg,
   306  				Tag:      "",
   307  			},
   308  			wantErr: true,
   309  			msg:     "Invalid timestamp",
   310  		},
   311  	}
   312  
   313  	for _, test := range tests {
   314  		test.expectedUserSigEx.Obj = test.userSig
   315  
   316  		userSigEx, err := createAppProtectUserSigEx(test.userSig)
   317  		if (err != nil) != test.wantErr {
   318  			t.Errorf("createAppProtectUserSigEx() returned %v, for the case of %s", err, test.msg)
   319  		}
   320  		if diff := cmp.Diff(test.expectedUserSigEx, userSigEx); diff != "" {
   321  			t.Errorf("createAppProtectUserSigEx() %q returned unexpected result (-want +got):\n%s", test.msg, diff)
   322  		}
   323  	}
   324  }
   325  
   326  func TestIsReqSatisfiedByUserSig(t *testing.T) {
   327  	userSigEx := &UserSigEx{Tag: "test", RevTime: parseTime("2020-06-16T18:32:01Z")}
   328  	userSigExNoRevTime := &UserSigEx{Tag: "test"}
   329  	tests := []struct {
   330  		sigReq   SignatureReq
   331  		sigEx    *UserSigEx
   332  		msg      string
   333  		expected bool
   334  	}{
   335  		{
   336  			sigReq: SignatureReq{
   337  				Tag: "test",
   338  				RevTimes: &RevTimes{
   339  					MinRevTime: parseTime("2020-01-21T18:32:02Z"),
   340  					MaxRevTime: parseTime("2020-10-23T18:32:02Z"),
   341  				},
   342  			},
   343  			sigEx:    userSigEx,
   344  			msg:      "Valid, Basic case",
   345  			expected: true,
   346  		},
   347  		{
   348  			sigReq: SignatureReq{
   349  				Tag: "test",
   350  				RevTimes: &RevTimes{
   351  					MinRevTime: parseTime("2021-01-21T18:32:02Z"),
   352  					MaxRevTime: parseTime("2022-01-23T18:32:02Z"),
   353  				},
   354  			},
   355  			sigEx:    userSigEx,
   356  			msg:      "Invalid, rev not in Required period",
   357  			expected: false,
   358  		},
   359  		{
   360  			sigReq: SignatureReq{
   361  				Tag: "test",
   362  				RevTimes: &RevTimes{
   363  					MaxRevTime: parseTime("2022-01-23T18:32:02Z"),
   364  				},
   365  			},
   366  			sigEx:    userSigEx,
   367  			msg:      "Valid, max rev time only",
   368  			expected: true,
   369  		},
   370  		{
   371  			sigReq: SignatureReq{
   372  				Tag: "test",
   373  				RevTimes: &RevTimes{
   374  					MaxRevTime: parseTime("2019-01-23T18:32:02Z"),
   375  				},
   376  			},
   377  			sigEx:    userSigEx,
   378  			msg:      "Invalid, max rev time only",
   379  			expected: false,
   380  		},
   381  		{
   382  			sigReq: SignatureReq{
   383  				Tag: "test",
   384  				RevTimes: &RevTimes{
   385  					MinRevTime: parseTime("2019-01-23T18:32:02Z"),
   386  				},
   387  			},
   388  			sigEx:    userSigEx,
   389  			msg:      "Valid, min rev time only",
   390  			expected: true,
   391  		},
   392  		{
   393  			sigReq: SignatureReq{
   394  				Tag: "test",
   395  				RevTimes: &RevTimes{
   396  					MinRevTime: parseTime("2022-01-23T18:32:02Z"),
   397  				},
   398  			},
   399  			sigEx:    userSigEx,
   400  			msg:      "Invalid, min rev time only",
   401  			expected: false,
   402  		},
   403  		{
   404  			sigReq: SignatureReq{
   405  				Tag: "testing",
   406  				RevTimes: &RevTimes{
   407  					MinRevTime: parseTime("2022-01-23T18:32:02Z"),
   408  				},
   409  			},
   410  			sigEx:    userSigEx,
   411  			msg:      "Invalid, different tag",
   412  			expected: false,
   413  		},
   414  		{
   415  			sigReq: SignatureReq{
   416  				Tag:      "testing",
   417  				RevTimes: &RevTimes{},
   418  			},
   419  			sigEx:    userSigEx,
   420  			msg:      "Invalid, different tag, no revTimes",
   421  			expected: false,
   422  		},
   423  		{
   424  			sigReq: SignatureReq{
   425  				Tag: "test",
   426  			},
   427  			sigEx:    userSigEx,
   428  			msg:      "Valid, matching tag, no revTimes",
   429  			expected: true,
   430  		},
   431  		{
   432  			sigReq: SignatureReq{
   433  				Tag: "test",
   434  				RevTimes: &RevTimes{
   435  					MinRevTime: parseTime("2019-01-23T18:32:02Z"),
   436  				},
   437  			},
   438  			sigEx:    userSigExNoRevTime,
   439  			msg:      "Valid, no RevDateTime",
   440  			expected: true,
   441  		},
   442  	}
   443  
   444  	for _, test := range tests {
   445  		result := isReqSatisfiedByUserSig(test.sigReq, test.sigEx)
   446  		if result != test.expected {
   447  			t.Errorf("Unexpected result in test case %s: got %v, expected: %v", test.msg, result, test.expected)
   448  		}
   449  	}
   450  }
   451  
   452  func TestAddOrUpdatePolicy(t *testing.T) {
   453  	basicTestPolicy := &unstructured.Unstructured{
   454  		Object: map[string]interface{}{
   455  			"metadata": map[string]interface{}{
   456  				"namespace": "testing",
   457  			},
   458  			"spec": map[string]interface{}{
   459  				"policy": map[string]interface{}{
   460  					"name": "TestPolicy",
   461  					"signature-requirements": []interface{}{
   462  						map[string]interface{}{
   463  							"maxRevisionDatetime": "2019-04-01T18:32:02Z",
   464  							"tag":                 "test",
   465  						},
   466  					},
   467  				},
   468  			},
   469  		},
   470  	}
   471  	basicTestPolicyNoReqs := &unstructured.Unstructured{
   472  		Object: map[string]interface{}{
   473  			"metadata": map[string]interface{}{
   474  				"namespace": "testing",
   475  			},
   476  			"spec": map[string]interface{}{
   477  				"policy": map[string]interface{}{
   478  					"name": "TestPolicy",
   479  				},
   480  			},
   481  		},
   482  	}
   483  	invalidTestPolicy := &unstructured.Unstructured{
   484  		Object: map[string]interface{}{
   485  			"metadata": map[string]interface{}{
   486  				"namespace": "testing",
   487  			},
   488  			"spec": map[string]interface{}{},
   489  		},
   490  	}
   491  	testPolicyUnsatisfied := &unstructured.Unstructured{
   492  		Object: map[string]interface{}{
   493  			"metadata": map[string]interface{}{
   494  				"namespace": "testing",
   495  			},
   496  			"spec": map[string]interface{}{
   497  				"policy": map[string]interface{}{
   498  					"name": "TestPolicy",
   499  					"signature-requirements": []interface{}{
   500  						map[string]interface{}{
   501  							"minRevisionDatetime": "2021-04-01T18:32:02Z",
   502  							"tag":                 "test",
   503  						},
   504  					},
   505  				},
   506  			},
   507  		},
   508  	}
   509  	apc := newConfigurationImpl()
   510  	apc.UserSigs["testing/TestUsersig"] = &UserSigEx{Tag: "test", RevTime: parseTime("2019-01-01T18:32:02Z"), IsValid: true}
   511  	tests := []struct {
   512  		policy           *unstructured.Unstructured
   513  		expectedChanges  []Change
   514  		expectedProblems []Problem
   515  		msg              string
   516  	}{
   517  		{
   518  			policy: basicTestPolicy,
   519  			expectedChanges: []Change{
   520  				{Resource: &PolicyEx{
   521  					Obj:     basicTestPolicy,
   522  					IsValid: true,
   523  					SignatureReqs: []SignatureReq{
   524  						{Tag: "test",
   525  							RevTimes: &RevTimes{
   526  								MaxRevTime: parseTime("2019-04-01T18:32:02Z"),
   527  							},
   528  						},
   529  					},
   530  				},
   531  					Op: AddOrUpdate,
   532  				},
   533  			},
   534  			expectedProblems: nil,
   535  			msg:              "Basic Case with sig reqs",
   536  		},
   537  		{
   538  			policy: basicTestPolicyNoReqs,
   539  			expectedChanges: []Change{
   540  				{Resource: &PolicyEx{
   541  					Obj:           basicTestPolicyNoReqs,
   542  					IsValid:       true,
   543  					SignatureReqs: []SignatureReq{},
   544  				},
   545  					Op: AddOrUpdate,
   546  				},
   547  			},
   548  			expectedProblems: nil,
   549  			msg:              "basic case no sig reqs",
   550  		},
   551  		{
   552  			policy: invalidTestPolicy,
   553  			expectedChanges: []Change{
   554  				{Resource: &PolicyEx{
   555  					Obj:      invalidTestPolicy,
   556  					IsValid:  false,
   557  					ErrorMsg: "Validation Failed",
   558  				},
   559  					Op: Delete,
   560  				},
   561  			},
   562  			expectedProblems: []Problem{
   563  				{
   564  					Object:  invalidTestPolicy,
   565  					Reason:  "Rejected",
   566  					Message: "Error validating policy : Error validating App Protect Policy : Required field map[] not found",
   567  				},
   568  			},
   569  			msg: "validation failed",
   570  		},
   571  		{
   572  			policy: testPolicyUnsatisfied,
   573  			expectedChanges: []Change{
   574  				{Resource: &PolicyEx{
   575  					Obj:      testPolicyUnsatisfied,
   576  					IsValid:  false,
   577  					ErrorMsg: "Policy has unsatisfied signature requirements",
   578  					SignatureReqs: []SignatureReq{
   579  						{Tag: "test",
   580  							RevTimes: &RevTimes{
   581  								MinRevTime: parseTime("2021-04-01T18:32:02Z"),
   582  							},
   583  						},
   584  					},
   585  				},
   586  					Op: Delete,
   587  				},
   588  			},
   589  			expectedProblems: []Problem{
   590  				{
   591  					Object:  testPolicyUnsatisfied,
   592  					Reason:  "Rejected",
   593  					Message: "Policy has unsatisfied signature requirements",
   594  				},
   595  			},
   596  			msg: "Missing sig reqs",
   597  		},
   598  	}
   599  	for _, test := range tests {
   600  		aPChans, aPProbs := apc.AddOrUpdatePolicy(test.policy)
   601  		if diff := cmp.Diff(test.expectedChanges, aPChans); diff != "" {
   602  			t.Errorf("AddOrUpdatePolicy() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
   603  		}
   604  		if diff := cmp.Diff(test.expectedProblems, aPProbs); diff != "" {
   605  			t.Errorf("AddOrUpdatePolicy() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
   606  		}
   607  	}
   608  }
   609  
   610  func TestAddOrUpdateLogConf(t *testing.T) {
   611  	validLogConf := &unstructured.Unstructured{
   612  		Object: map[string]interface{}{
   613  			"metadata": map[string]interface{}{
   614  				"namespace": "testing",
   615  				"name":      "testlogconf",
   616  			},
   617  			"spec": map[string]interface{}{
   618  				"content": map[string]interface{}{},
   619  				"filter":  map[string]interface{}{},
   620  			},
   621  		},
   622  	}
   623  	invalidLogConf := &unstructured.Unstructured{
   624  		Object: map[string]interface{}{
   625  			"metadata": map[string]interface{}{
   626  				"namespace": "testing",
   627  				"name":      "testlogconf",
   628  			},
   629  			"spec": map[string]interface{}{
   630  				"content": map[string]interface{}{},
   631  			},
   632  		},
   633  	}
   634  	apc := NewConfiguration()
   635  	tests := []struct {
   636  		logconf          *unstructured.Unstructured
   637  		expectedChanges  []Change
   638  		expectedProblems []Problem
   639  		msg              string
   640  	}{
   641  		{
   642  			logconf: validLogConf,
   643  			expectedChanges: []Change{
   644  				{Resource: &LogConfEx{
   645  					Obj:     validLogConf,
   646  					IsValid: true,
   647  				},
   648  					Op: AddOrUpdate,
   649  				},
   650  			},
   651  			expectedProblems: nil,
   652  			msg:              "Basic Case",
   653  		},
   654  		{
   655  			logconf: invalidLogConf,
   656  			expectedChanges: []Change{
   657  				{Resource: &LogConfEx{
   658  					Obj:      invalidLogConf,
   659  					IsValid:  false,
   660  					ErrorMsg: "Validation Failed",
   661  				},
   662  					Op: Delete,
   663  				},
   664  			},
   665  			expectedProblems: []Problem{
   666  				{
   667  					Object:  invalidLogConf,
   668  					Reason:  "Rejected",
   669  					Message: "Error validating App Protect Log Configuration testlogconf: Required field map[] not found",
   670  				},
   671  			},
   672  			msg: "validation failed",
   673  		},
   674  	}
   675  	for _, test := range tests {
   676  		aPChans, aPProbs := apc.AddOrUpdateLogConf(test.logconf)
   677  		if diff := cmp.Diff(test.expectedChanges, aPChans); diff != "" {
   678  			t.Errorf("AddOrUpdateLogConf() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
   679  		}
   680  		if diff := cmp.Diff(test.expectedProblems, aPProbs); diff != "" {
   681  			t.Errorf("AddOrUpdateLogConf() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
   682  		}
   683  	}
   684  }
   685  
   686  func TestAddOrUpdateUserSig(t *testing.T) {
   687  	testUserSig1 := &unstructured.Unstructured{
   688  		Object: map[string]interface{}{
   689  			"metadata": map[string]interface{}{
   690  				"namespace":         "testing",
   691  				"name":              "test1",
   692  				"uid":               "1",
   693  				"creationTimestamp": "2020-01-23T18:32:02Z",
   694  			},
   695  			"spec": map[string]interface{}{
   696  				"signatures": []interface{}{
   697  					map[string]interface{}{},
   698  				},
   699  				"revisionDatetime": "2020-01-23T18:32:02Z",
   700  				"tag":              "test1",
   701  			},
   702  		},
   703  	}
   704  	testUserSig2 := &unstructured.Unstructured{
   705  		Object: map[string]interface{}{
   706  			"metadata": map[string]interface{}{
   707  				"namespace":         "testing",
   708  				"name":              "test2",
   709  				"uid":               "2",
   710  				"creationTimestamp": "2020-01-23T18:32:02Z",
   711  			},
   712  			"spec": map[string]interface{}{
   713  				"signatures": []interface{}{
   714  					map[string]interface{}{},
   715  				},
   716  				"revisionDatetime": "2020-01-23T18:32:02Z",
   717  				"tag":              "test2",
   718  			},
   719  		},
   720  	}
   721  	invalidTestUserSig2 := &unstructured.Unstructured{
   722  		Object: map[string]interface{}{
   723  			"metadata": map[string]interface{}{
   724  				"namespace":         "testing",
   725  				"name":              "test2",
   726  				"uid":               "3",
   727  				"creationTimestamp": "2020-01-23T18:32:02Z",
   728  			},
   729  			"spec": map[string]interface{}{
   730  				"revisionDatetime": "2020-01-23T18:32:02Z",
   731  				"tag":              "test2",
   732  			},
   733  		},
   734  	}
   735  	testUserSigDupTag := &unstructured.Unstructured{
   736  		Object: map[string]interface{}{
   737  			"metadata": map[string]interface{}{
   738  				"namespace":         "testing",
   739  				"name":              "test2",
   740  				"uid":               "4",
   741  				"creationTimestamp": "2020-01-25T18:32:02Z",
   742  			},
   743  			"spec": map[string]interface{}{
   744  				"signatures": []interface{}{
   745  					map[string]interface{}{},
   746  				},
   747  				"revisionDatetime": "2020-01-23T18:32:02Z",
   748  				"tag":              "test1",
   749  			},
   750  		},
   751  	}
   752  	testUserSig1Invalid := &unstructured.Unstructured{
   753  		Object: map[string]interface{}{
   754  			"metadata": map[string]interface{}{
   755  				"namespace":         "testing",
   756  				"name":              "test1",
   757  				"uid":               "1",
   758  				"creationTimestamp": "2020-01-23T18:32:02Z",
   759  			},
   760  		},
   761  	}
   762  	testUserSig3 := &unstructured.Unstructured{
   763  		Object: map[string]interface{}{
   764  			"metadata": map[string]interface{}{
   765  				"namespace":         "testing",
   766  				"name":              "test3",
   767  				"uid":               "5",
   768  				"creationTimestamp": "2020-01-23T18:32:02Z",
   769  			},
   770  			"spec": map[string]interface{}{
   771  				"signatures": []interface{}{
   772  					map[string]interface{}{},
   773  				},
   774  				"revisionDatetime": "2020-01-23T18:32:02Z",
   775  				"tag":              "test3",
   776  			},
   777  		},
   778  	}
   779  
   780  	appProtectConfiguration := newConfigurationImpl()
   781  	appProtectConfiguration.UserSigs["testing/test1"] = &UserSigEx{
   782  		Obj:      testUserSig1,
   783  		Tag:      "test1",
   784  		IsValid:  true,
   785  		ErrorMsg: "",
   786  	}
   787  	appProtectConfiguration.Policies["testing/testpolicy"] = &PolicyEx{
   788  		Obj:      &unstructured.Unstructured{Object: map[string]interface{}{}},
   789  		IsValid:  false,
   790  		ErrorMsg: "Policy has unsatisfied signature requirements",
   791  		SignatureReqs: []SignatureReq{
   792  			{
   793  				Tag: "test3",
   794  				RevTimes: &RevTimes{
   795  					MinRevTime: parseTime("2010-01-23T18:32:02Z"),
   796  				},
   797  			},
   798  		},
   799  	}
   800  	tests := []struct {
   801  		usersig               *unstructured.Unstructured
   802  		expectedUserSigChange UserSigChange
   803  		expectedProblems      []Problem
   804  		msg                   string
   805  	}{
   806  		{
   807  			usersig: testUserSig2,
   808  			expectedUserSigChange: UserSigChange{
   809  				UserSigs: []*unstructured.Unstructured{
   810  					testUserSig1,
   811  					testUserSig2,
   812  				},
   813  			},
   814  			msg: "Basic case",
   815  		},
   816  		{
   817  			usersig: invalidTestUserSig2,
   818  			expectedUserSigChange: UserSigChange{
   819  				UserSigs: []*unstructured.Unstructured{
   820  					testUserSig1,
   821  				},
   822  			},
   823  			expectedProblems: []Problem{
   824  				{
   825  					Object:  invalidTestUserSig2,
   826  					Reason:  "Rejected",
   827  					Message: "Validation Failed",
   828  				},
   829  			},
   830  			msg: "validation failed",
   831  		},
   832  		{
   833  			usersig: testUserSigDupTag,
   834  			expectedUserSigChange: UserSigChange{
   835  				UserSigs: []*unstructured.Unstructured{
   836  					testUserSig1,
   837  				},
   838  			},
   839  			expectedProblems: []Problem{
   840  				{
   841  					Object:  testUserSigDupTag,
   842  					Message: "Duplicate tag set",
   843  					Reason:  "Rejected",
   844  				},
   845  			},
   846  			msg: "Duplicate tags",
   847  		},
   848  		{
   849  			usersig: testUserSig1Invalid,
   850  			expectedUserSigChange: UserSigChange{
   851  				UserSigs: []*unstructured.Unstructured{
   852  					testUserSigDupTag,
   853  				},
   854  			},
   855  			expectedProblems: []Problem{
   856  				{
   857  					Object:  testUserSig1Invalid,
   858  					Message: "Validation Failed",
   859  					Reason:  "Rejected",
   860  				},
   861  			},
   862  			msg: "UserSig becomes valid after previous tag holder became invalid",
   863  		},
   864  		{
   865  			usersig: testUserSig3,
   866  			expectedUserSigChange: UserSigChange{
   867  				PolicyAddsOrUpdates: []*unstructured.Unstructured{
   868  					{
   869  						Object: map[string]interface{}{},
   870  					},
   871  				},
   872  				UserSigs: []*unstructured.Unstructured{
   873  					testUserSigDupTag,
   874  					testUserSig3,
   875  				},
   876  			},
   877  			msg: "Policy becomes valid after a UserSig with the right tag was added",
   878  		},
   879  	}
   880  
   881  	for _, test := range tests {
   882  		apUserSigChan, apProbs := appProtectConfiguration.AddOrUpdateUserSig(test.usersig)
   883  		if diff := cmp.Diff(test.expectedUserSigChange, apUserSigChan, unstructuredSliceCmpOpts); diff != "" {
   884  			t.Errorf("AddOrUpdateUserSig() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
   885  		}
   886  		if diff := cmp.Diff(test.expectedProblems, apProbs); diff != "" {
   887  			t.Errorf("AddOrUpdateUserSig() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
   888  		}
   889  	}
   890  }
   891  
   892  func TestDeletePolicy(t *testing.T) {
   893  	appProtectConfiguration := newConfigurationImpl()
   894  	appProtectConfiguration.Policies["testing/test"] = &PolicyEx{}
   895  	tests := []struct {
   896  		key              string
   897  		expectedChanges  []Change
   898  		expectedProblems []Problem
   899  		msg              string
   900  	}{
   901  		{
   902  			key: "testing/test",
   903  			expectedChanges: []Change{
   904  				{
   905  					Op:       Delete,
   906  					Resource: &PolicyEx{},
   907  				},
   908  			},
   909  			expectedProblems: nil,
   910  			msg:              "Positive",
   911  		},
   912  		{
   913  			key:              "testing/notpresent",
   914  			expectedChanges:  nil,
   915  			expectedProblems: nil,
   916  			msg:              "Negative",
   917  		},
   918  	}
   919  	for _, test := range tests {
   920  		apChan, apProbs := appProtectConfiguration.DeletePolicy(test.key)
   921  		if diff := cmp.Diff(test.expectedChanges, apChan); diff != "" {
   922  			t.Errorf("DeletePolicy() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
   923  		}
   924  		if diff := cmp.Diff(test.expectedProblems, apProbs); diff != "" {
   925  			t.Errorf("DeletePolicy() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
   926  		}
   927  	}
   928  }
   929  
   930  func TestDeleteLogConf(t *testing.T) {
   931  	appProtectConfiguration := newConfigurationImpl()
   932  	appProtectConfiguration.LogConfs["testing/test"] = &LogConfEx{}
   933  	tests := []struct {
   934  		key              string
   935  		expectedChanges  []Change
   936  		expectedProblems []Problem
   937  		msg              string
   938  	}{
   939  		{
   940  			key: "testing/test",
   941  			expectedChanges: []Change{
   942  				{
   943  					Op:       Delete,
   944  					Resource: &LogConfEx{},
   945  				},
   946  			},
   947  			expectedProblems: nil,
   948  			msg:              "Positive",
   949  		},
   950  		{
   951  			key:              "testing/notpresent",
   952  			expectedChanges:  nil,
   953  			expectedProblems: nil,
   954  			msg:              "Negative",
   955  		},
   956  	}
   957  	for _, test := range tests {
   958  		apChan, apProbs := appProtectConfiguration.DeleteLogConf(test.key)
   959  		if diff := cmp.Diff(test.expectedChanges, apChan); diff != "" {
   960  			t.Errorf("DeleteLogConf() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
   961  		}
   962  		if diff := cmp.Diff(test.expectedProblems, apProbs); diff != "" {
   963  			t.Errorf("DeleteLogConf() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
   964  		}
   965  	}
   966  }
   967  
   968  func TestDeleteUserSig(t *testing.T) {
   969  	testUserSig1 := &unstructured.Unstructured{
   970  		Object: map[string]interface{}{
   971  			"metadata": map[string]interface{}{
   972  				"namespace":         "testing",
   973  				"name":              "test1",
   974  				"uid":               "1",
   975  				"creationTimestamp": "2020-01-23T18:32:02Z",
   976  			},
   977  			"spec": map[string]interface{}{
   978  				"signatures": []interface{}{
   979  					map[string]interface{}{},
   980  				},
   981  				"revisionDatetime": "2020-01-23T18:32:02Z",
   982  				"tag":              "test1",
   983  			},
   984  		},
   985  	}
   986  	testUserSig2 := &unstructured.Unstructured{
   987  		Object: map[string]interface{}{
   988  			"metadata": map[string]interface{}{
   989  				"namespace":         "testing",
   990  				"name":              "test2",
   991  				"uid":               "2",
   992  				"creationTimestamp": "2020-01-23T18:32:02Z",
   993  			},
   994  			"spec": map[string]interface{}{
   995  				"signatures": []interface{}{
   996  					map[string]interface{}{},
   997  				},
   998  				"revisionDatetime": "2020-01-23T18:32:02Z",
   999  				"tag":              "test2",
  1000  			},
  1001  		},
  1002  	}
  1003  	appProtectConfiguration := newConfigurationImpl()
  1004  	appProtectConfiguration.UserSigs["testing/test1"] = &UserSigEx{
  1005  		IsValid: true,
  1006  		Obj:     testUserSig1,
  1007  	}
  1008  	appProtectConfiguration.UserSigs["testing/test2"] = &UserSigEx{
  1009  		IsValid: true,
  1010  		Obj:     testUserSig2,
  1011  	}
  1012  	appProtectConfiguration.Policies["testing/testpolicy"] = &PolicyEx{
  1013  		Obj:      &unstructured.Unstructured{Object: map[string]interface{}{}},
  1014  		IsValid:  true,
  1015  		ErrorMsg: "",
  1016  		SignatureReqs: []SignatureReq{
  1017  			{
  1018  				Tag: "test1",
  1019  				RevTimes: &RevTimes{
  1020  					MinRevTime: parseTime("2010-01-23T18:32:02Z"),
  1021  				},
  1022  			},
  1023  		},
  1024  	}
  1025  	tests := []struct {
  1026  		key              string
  1027  		expectedChange   UserSigChange
  1028  		expectedProblems []Problem
  1029  		msg              string
  1030  	}{
  1031  		{
  1032  			key: "testing/test1",
  1033  			expectedChange: UserSigChange{
  1034  				PolicyDeletions: []*unstructured.Unstructured{
  1035  					{
  1036  						Object: map[string]interface{}{},
  1037  					},
  1038  				},
  1039  				UserSigs: []*unstructured.Unstructured{
  1040  					testUserSig2,
  1041  				},
  1042  			},
  1043  			expectedProblems: []Problem{
  1044  				{
  1045  					Reason:  "Rejected",
  1046  					Message: "Policy has unsatisfied signature requirements",
  1047  					Object: &unstructured.Unstructured{
  1048  						Object: map[string]interface{}{},
  1049  					},
  1050  				},
  1051  			},
  1052  			msg: "Positive, policy gets set to invalid",
  1053  		},
  1054  		{
  1055  			key:              "testing/test3",
  1056  			expectedChange:   UserSigChange{},
  1057  			expectedProblems: nil,
  1058  			msg:              "Negative",
  1059  		},
  1060  	}
  1061  
  1062  	for _, test := range tests {
  1063  		apChan, apProbs := appProtectConfiguration.DeleteUserSig(test.key)
  1064  		if diff := cmp.Diff(test.expectedChange, apChan, unstructuredSliceCmpOpts); diff != "" {
  1065  			t.Errorf("DeleteUserSig() %q changes returned unexpected result (-want +got):\n%s", test.msg, diff)
  1066  		}
  1067  		if diff := cmp.Diff(test.expectedProblems, apProbs); diff != "" {
  1068  			t.Errorf("DeleteUserSig() %q problems returned unexpected result (-want +got):\n%s", test.msg, diff)
  1069  		}
  1070  	}
  1071  }
  1072  
  1073  func TestGetAppProtectResource(t *testing.T) {
  1074  	tests := []struct {
  1075  		kind    string
  1076  		key     string
  1077  		wantErr bool
  1078  		errMsg  string
  1079  		msg     string
  1080  	}{
  1081  		{
  1082  			kind:    "APPolicy",
  1083  			key:     "testing/test1",
  1084  			wantErr: false,
  1085  			msg:     "Policy, positive",
  1086  		},
  1087  		{
  1088  			kind:    "APPolicy",
  1089  			key:     "testing/test2",
  1090  			wantErr: true,
  1091  			errMsg:  "Validation Failed",
  1092  			msg:     "Policy, Negative, invalid object",
  1093  		},
  1094  		{
  1095  			kind:    "APPolicy",
  1096  			key:     "testing/test3",
  1097  			wantErr: true,
  1098  			errMsg:  "App Protect Policy testing/test3 not found",
  1099  			msg:     "Policy, Negative, Object Does not exist",
  1100  		},
  1101  		{
  1102  			kind:    "APLogConf",
  1103  			key:     "testing/test1",
  1104  			wantErr: false,
  1105  			msg:     "LogConf, positive",
  1106  		},
  1107  		{
  1108  			kind:    "APLogConf",
  1109  			key:     "testing/test2",
  1110  			wantErr: true,
  1111  			errMsg:  "Validation Failed",
  1112  			msg:     "LogConf, Negative, invalid object",
  1113  		},
  1114  		{
  1115  			kind:    "APLogConf",
  1116  			key:     "testing/test3",
  1117  			wantErr: true,
  1118  			errMsg:  "App Protect LogConf testing/test3 not found",
  1119  			msg:     "LogConf, Negative, Object Does not exist",
  1120  		},
  1121  		{
  1122  			kind:    "APUserSig",
  1123  			key:     "testing/test1",
  1124  			wantErr: false,
  1125  			msg:     "UserSig, positive",
  1126  		},
  1127  		{
  1128  			kind:    "APUserSig",
  1129  			key:     "testing/test2",
  1130  			wantErr: true,
  1131  			errMsg:  "Validation Failed",
  1132  			msg:     "UserSig, Negative, invalid object",
  1133  		},
  1134  		{
  1135  			kind:    "APUserSig",
  1136  			key:     "testing/test3",
  1137  			wantErr: true,
  1138  			errMsg:  "App Protect UserSig testing/test3 not found",
  1139  			msg:     "UserSig, Negative, Object Does not exist",
  1140  		},
  1141  		{
  1142  			kind:    "Notreal",
  1143  			key:     "testing/test3",
  1144  			wantErr: true,
  1145  			errMsg:  "Unknown App Protect resource kind Notreal",
  1146  			msg:     "Ivalid kind, Negative",
  1147  		},
  1148  	}
  1149  	appProtectConfiguration := newConfigurationImpl()
  1150  	appProtectConfiguration.Policies["testing/test1"] = &PolicyEx{IsValid: true, Obj: &unstructured.Unstructured{}}
  1151  	appProtectConfiguration.Policies["testing/test2"] = &PolicyEx{IsValid: false, Obj: &unstructured.Unstructured{}, ErrorMsg: "Validation Failed"}
  1152  	appProtectConfiguration.LogConfs["testing/test1"] = &LogConfEx{IsValid: true, Obj: &unstructured.Unstructured{}}
  1153  	appProtectConfiguration.LogConfs["testing/test2"] = &LogConfEx{IsValid: false, Obj: &unstructured.Unstructured{}, ErrorMsg: "Validation Failed"}
  1154  	appProtectConfiguration.UserSigs["testing/test1"] = &UserSigEx{IsValid: true, Obj: &unstructured.Unstructured{}}
  1155  	appProtectConfiguration.UserSigs["testing/test2"] = &UserSigEx{IsValid: false, Obj: &unstructured.Unstructured{}, ErrorMsg: "Validation Failed"}
  1156  
  1157  	for _, test := range tests {
  1158  		_, err := appProtectConfiguration.GetAppResource(test.kind, test.key)
  1159  		if (err != nil) != test.wantErr {
  1160  			t.Errorf("GetAppResource() returned %v on case %s", err, test.msg)
  1161  		}
  1162  		if test.wantErr || err != nil {
  1163  			if test.errMsg != err.Error() {
  1164  				t.Errorf("GetAppResource() returned error message %s on case %s (expected %s)", err.Error(), test.msg, test.errMsg)
  1165  			}
  1166  		}
  1167  	}
  1168  }