github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/lookup/lookup_test.go (about)

     1  // +build !windows
     2  
     3  package lookup
     4  
     5  import (
     6  	"testing"
     7  
     8  	. "github.com/smartystreets/goconvey/convey"
     9  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    10  )
    11  
    12  var (
    13  	appEqWeb = policy.KeyValueOperator{
    14  		Key:      "app",
    15  		Value:    []string{"web"},
    16  		Operator: policy.Equal,
    17  		ID:       "1",
    18  	}
    19  	envEqDemo = policy.KeyValueOperator{
    20  		Key:      "env",
    21  		Value:    []string{"demo"},
    22  		Operator: policy.Equal,
    23  		ID:       "2",
    24  	}
    25  
    26  	envEqDemoOrQa = policy.KeyValueOperator{
    27  		Key:      "env",
    28  		Value:    []string{"demo", "qa"},
    29  		Operator: policy.Equal,
    30  		ID:       "3",
    31  	}
    32  
    33  	dcKeyExists = policy.KeyValueOperator{
    34  		Key:      "dc",
    35  		Operator: policy.KeyExists,
    36  	}
    37  
    38  	langNotJava = policy.KeyValueOperator{
    39  		Key:      "lang",
    40  		Value:    []string{"java"},
    41  		Operator: policy.NotEqual,
    42  	}
    43  
    44  	envNotDemoOrQA = policy.KeyValueOperator{
    45  		Key:      "env",
    46  		Value:    []string{"demo", "qa"},
    47  		Operator: policy.NotEqual,
    48  	}
    49  
    50  	envKeyNotExists = policy.KeyValueOperator{
    51  		Key:      "env",
    52  		Operator: policy.KeyNotExists,
    53  	}
    54  
    55  	vulnerKey = policy.KeyValueOperator{
    56  		Key:      "vulnerability",
    57  		Value:    []string{"high"},
    58  		Operator: policy.Equal,
    59  	}
    60  
    61  	vulnerLowKey = policy.KeyValueOperator{
    62  		Key:      "vulnerability",
    63  		Value:    []string{"low"},
    64  		Operator: policy.Equal,
    65  	}
    66  
    67  	namespaceKey = policy.KeyValueOperator{
    68  		Key:      "namespace",
    69  		Value:    []string{"/a/b/*"},
    70  		Operator: policy.Equal,
    71  	}
    72  
    73  	appEqWebAndenvEqDemo = policy.TagSelector{
    74  		Clause: []policy.KeyValueOperator{appEqWeb, envEqDemo},
    75  		Policy: &policy.FlowPolicy{Action: policy.Accept},
    76  	}
    77  
    78  	appEqWebAndEnvEqDemoOrQa = policy.TagSelector{
    79  		Clause: []policy.KeyValueOperator{appEqWeb, envEqDemoOrQa},
    80  		Policy: &policy.FlowPolicy{Action: policy.Accept},
    81  	}
    82  
    83  	dcTagExists = policy.TagSelector{
    84  		Clause: []policy.KeyValueOperator{dcKeyExists},
    85  		Policy: &policy.FlowPolicy{Action: policy.Accept},
    86  	}
    87  
    88  	policylangNotJava = policy.TagSelector{
    89  		Clause: []policy.KeyValueOperator{langNotJava},
    90  		Policy: &policy.FlowPolicy{Action: policy.Accept},
    91  	}
    92  
    93  	appEqWebAndenvNotDemoOrQA = policy.TagSelector{
    94  		Clause: []policy.KeyValueOperator{appEqWeb, envNotDemoOrQA},
    95  		Policy: &policy.FlowPolicy{Action: policy.Accept},
    96  	}
    97  
    98  	envKeyNotExistsAndAppEqWeb = policy.TagSelector{
    99  		Clause: []policy.KeyValueOperator{envKeyNotExists, appEqWeb},
   100  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   101  	}
   102  
   103  	vulnTagPolicy = policy.TagSelector{
   104  		Clause: []policy.KeyValueOperator{vulnerKey},
   105  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   106  	}
   107  
   108  	policyNamespace = policy.TagSelector{
   109  		Clause: []policy.KeyValueOperator{namespaceKey, vulnerLowKey},
   110  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   111  	}
   112  
   113  	domainParent = policy.KeyValueOperator{
   114  		Key:      "domain",
   115  		Value:    []string{"com.example.*", "com.*", "com.longexample.*", "com.ex.*"},
   116  		Operator: policy.Equal,
   117  	}
   118  
   119  	domainFull = policy.KeyValueOperator{
   120  		Key:      "domain",
   121  		Value:    []string{"com.example.web"},
   122  		Operator: policy.Equal,
   123  	}
   124  
   125  	policyDomainParent = policy.TagSelector{
   126  		Clause: []policy.KeyValueOperator{domainParent},
   127  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   128  	}
   129  
   130  	policyDomainFull = policy.TagSelector{
   131  		Clause: []policy.KeyValueOperator{domainFull},
   132  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   133  	}
   134  
   135  	policyEnvDoesNotExist = policy.TagSelector{
   136  		Clause: []policy.KeyValueOperator{envKeyNotExists},
   137  		Policy: &policy.FlowPolicy{Action: policy.Accept},
   138  	}
   139  )
   140  
   141  // TestConstructorNewPolicyDB tests the NewPolicyDB constructor
   142  func TestConstructorNewPolicyDB(t *testing.T) {
   143  	Convey("Given that I instantiate a new policy DB, I should not get nil", t, func() {
   144  
   145  		p := &PolicyDB{}
   146  
   147  		policyDB := NewPolicyDB()
   148  
   149  		So(policyDB, ShouldHaveSameTypeAs, p)
   150  	})
   151  }
   152  
   153  // TestFuncAddPolicy tests the add policy function
   154  func TestFuncAddPolicy(t *testing.T) {
   155  
   156  	Convey("Given an empty policy DB", t, func() {
   157  		policyDB := NewPolicyDB()
   158  
   159  		Convey("When I add a single policy it should be associated with all the tags", func() {
   160  			index := policyDB.AddPolicy(appEqWebAndenvEqDemo)
   161  
   162  			So(policyDB.numberOfPolicies, ShouldEqual, 1)
   163  			So(index, ShouldEqual, 1)
   164  			for _, c := range appEqWebAndenvEqDemo.Clause {
   165  				So(policyDB.equalMapTable[c.Key][c.Value[0]], ShouldNotBeNil)
   166  				So(policyDB.equalMapTable[c.Key][c.Value[0]][0].index, ShouldEqual, index)
   167  				So(policyDB.equalPrefixes[c.Key], ShouldNotContain, c.Key)
   168  			}
   169  		})
   170  
   171  		Convey("When I add a policy with the not equal operator, it should be added to the notEqual db", func() {
   172  			index := policyDB.AddPolicy(policylangNotJava)
   173  
   174  			So(policyDB.numberOfPolicies, ShouldEqual, 1)
   175  			So(index, ShouldEqual, 1)
   176  			for _, c := range policylangNotJava.Clause {
   177  				So(policyDB.notEqualMapTable[c.Key][c.Value[0]], ShouldNotBeNil)
   178  				So(policyDB.notEqualMapTable[c.Key][c.Value[0]][0].index, ShouldEqual, index)
   179  				So(policyDB.equalPrefixes, ShouldNotContainKey, c.Key)
   180  			}
   181  		})
   182  
   183  		Convey("When I add a policy with the KeyExists operator, it should be added as a prefix of 0", func() {
   184  			index := policyDB.AddPolicy(dcTagExists)
   185  
   186  			key := dcTagExists.Clause[0].Key
   187  			So(policyDB.numberOfPolicies, ShouldEqual, 1)
   188  			So(index, ShouldEqual, 1)
   189  			So(policyDB.equalPrefixes, ShouldContainKey, key)
   190  			So(policyDB.equalPrefixes[key], ShouldContain, 0)
   191  			So(policyDB.equalMapTable[key], ShouldHaveLength, 1)
   192  			So(policyDB.equalMapTable[key], ShouldContainKey, "")
   193  			So(policyDB.equalPrefixes[key], ShouldHaveLength, 1)
   194  		})
   195  
   196  		Convey("When I add a policy with prefixes, it should be associated with the right prefixes", func() {
   197  			index := policyDB.AddPolicy(policyDomainParent)
   198  
   199  			key := policyDomainParent.Clause[0].Key
   200  			value0 := policyDomainParent.Clause[0].Value[0]
   201  			value1 := policyDomainParent.Clause[0].Value[1]
   202  			value2 := policyDomainParent.Clause[0].Value[2]
   203  			value3 := policyDomainParent.Clause[0].Value[3]
   204  			So(policyDB.numberOfPolicies, ShouldEqual, 1)
   205  			So(index, ShouldEqual, 1)
   206  			So(policyDB.equalMapTable[key], ShouldHaveLength, 4)
   207  			So(policyDB.equalMapTable[key], ShouldContainKey, value0[:len(value0)-1])
   208  			So(policyDB.equalMapTable[key], ShouldContainKey, value1[:len(value1)-1])
   209  			So(policyDB.equalMapTable[key], ShouldContainKey, value2[:len(value2)-1])
   210  			So(policyDB.equalMapTable[key], ShouldContainKey, value3[:len(value3)-1])
   211  			So(policyDB.equalPrefixes[key], ShouldHaveLength, 4)
   212  			So(policyDB.equalPrefixes[key], ShouldContain, len(value0)-1)
   213  			So(policyDB.equalPrefixes[key], ShouldContain, len(value1)-1)
   214  			So(policyDB.equalPrefixes[key], ShouldContain, len(value2)-1)
   215  			So(policyDB.equalPrefixes[key], ShouldContain, len(value3)-1)
   216  		})
   217  
   218  	})
   219  }
   220  
   221  // TestFuncSearch tests the search function of the lookup
   222  func TestFuncSearch(t *testing.T) {
   223  	// policy1 : app=web and env=demo
   224  	// policy2 : lang != java
   225  	// policy3 : dc=*
   226  	// policy4: app=web and env IN (demo, qa)
   227  	// policy5: app=web and env NotIN (demo, qa)
   228  	// policy6: app=web not env=*
   229  	// policy7: domain IN ("com.*", "com.example.*")
   230  	// policy8: domain=com.example.web
   231  	// policy9: env doesn't exist
   232  	// policy10: vulnerability=high
   233  	// policy11: namespace=/a/b/* and vulnerability=low
   234  
   235  	Convey("Given an empty policyDB", t, func() {
   236  		policyDB := NewPolicyDB()
   237  		Convey("Given that I add two policy rules", func() {
   238  			index1 := policyDB.AddPolicy(appEqWebAndenvEqDemo)
   239  			index2 := policyDB.AddPolicy(policylangNotJava)
   240  			index3 := policyDB.AddPolicy(dcTagExists)
   241  			index4 := policyDB.AddPolicy(appEqWebAndEnvEqDemoOrQa)
   242  			index5 := policyDB.AddPolicy(appEqWebAndenvNotDemoOrQA)
   243  			index6 := policyDB.AddPolicy(envKeyNotExistsAndAppEqWeb)
   244  			index7 := policyDB.AddPolicy(policyDomainParent)
   245  			index8 := policyDB.AddPolicy(policyDomainFull)
   246  			index9 := policyDB.AddPolicy(policyEnvDoesNotExist)
   247  			index10 := policyDB.AddPolicy(vulnTagPolicy)
   248  			index11 := policyDB.AddPolicy(policyNamespace)
   249  
   250  			So(index1, ShouldEqual, 1)
   251  			So(index2, ShouldEqual, 2)
   252  			So(index3, ShouldEqual, 3)
   253  			So(index4, ShouldEqual, 4)
   254  			So(index5, ShouldEqual, 5)
   255  			So(index6, ShouldEqual, 6)
   256  			So(index9, ShouldEqual, 9)
   257  
   258  			Convey("The vulnerability tag policy should match", func() {
   259  				tags := policy.NewTagStore()
   260  				tags.AppendKeyValue("vulnerability", "high")
   261  
   262  				index, action := policyDB.Search(tags)
   263  				So(index, ShouldEqual, index10)
   264  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   265  			})
   266  
   267  			Convey("A policy that matches ID should match", func() {
   268  				tags := policy.NewTagStoreFromSlice([]string{"1"})
   269  				index, action := policyDB.Search(tags)
   270  				So(action, ShouldNotBeNil)
   271  				So(index, ShouldEqual, index6)
   272  			})
   273  
   274  			Convey("A policy that matches only the namespace, shoud not match", func() {
   275  				tags := policy.NewTagStore()
   276  				tags.AppendKeyValue("namespace", "/a/b/c/d")
   277  				tags.AppendKeyValue("env", "privatedemo")
   278  
   279  				index, action := policyDB.Search(tags)
   280  				So(action, ShouldBeNil)
   281  				So(index, ShouldEqual, -1)
   282  			})
   283  
   284  			Convey("A policy that matches namespace and vulnerability low, shoud match", func() {
   285  				tags := policy.NewTagStore()
   286  				tags.AppendKeyValue("namespace", "/a/b/c/d")
   287  				tags.AppendKeyValue("vulnerability", "low")
   288  				tags.AppendKeyValue("env", "privatedemo")
   289  
   290  				index, action := policyDB.Search(tags)
   291  				So(action, ShouldNotBeNil)
   292  				So(index, ShouldEqual, index11)
   293  			})
   294  
   295  			Convey("Given that I search for a single matching that matches the equal rules, it should return the correct index,", func() {
   296  				tags := policy.NewTagStore()
   297  				tags.AppendKeyValue("app", "web")
   298  				tags.AppendKeyValue("env", "demo")
   299  
   300  				index, action := policyDB.Search(tags)
   301  				So(index, ShouldEqual, index1)
   302  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   303  			})
   304  
   305  			Convey("Given that I search for a single matching that matches the not equal rules, it should return the right index,", func() {
   306  				tags := policy.NewTagStore()
   307  				tags.AppendKeyValue("lang", "go")
   308  				tags.AppendKeyValue("env", "demo")
   309  
   310  				index, action := policyDB.Search(tags)
   311  				So(index, ShouldEqual, index2)
   312  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   313  			})
   314  
   315  			Convey("Given that I search for rules that match the KeyExists Policy, it should return the right index  ", func() {
   316  				tags := policy.NewTagStore()
   317  				tags.AppendKeyValue("dc", "EAST")
   318  				tags.AppendKeyValue("env", "demo")
   319  
   320  				index, action := policyDB.Search(tags)
   321  				So(index, ShouldEqual, index3)
   322  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   323  			})
   324  
   325  			Convey("Given that I search for a single matching that matches the Or rules, it should return the right index,", func() {
   326  
   327  				tags := policy.NewTagStore()
   328  				tags.AppendKeyValue("app", "web")
   329  				tags.AppendKeyValue("env", "qa")
   330  
   331  				index, action := policyDB.Search(tags)
   332  				So(index, ShouldEqual, index4)
   333  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   334  			})
   335  
   336  			Convey("Given that I search for a single matching that matches the NOT Or rlues, it should return the right index,", func() {
   337  				tags := policy.NewTagStore()
   338  				tags.AppendKeyValue("app", "web")
   339  				tags.AppendKeyValue("env", "prod")
   340  
   341  				index, action := policyDB.Search(tags)
   342  				So(index, ShouldEqual, index5)
   343  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   344  			})
   345  
   346  			Convey("Given that I search for a single clause  that fails in the Not OR operator, it should fail ,", func() {
   347  				tags := policy.NewTagStore()
   348  				tags.AppendKeyValue("lang", "java")
   349  				tags.AppendKeyValue("env", "demo")
   350  				tags.AppendKeyValue("app", "db")
   351  
   352  				index, action := policyDB.Search(tags)
   353  				So(index, ShouldEqual, -1)
   354  				So(action, ShouldBeNil)
   355  			})
   356  
   357  			Convey("Given that I search for rules that do not match, it should return an error ", func() {
   358  				tags := policy.NewTagStore()
   359  				tags.AppendKeyValue("tag", "node")
   360  				tags.AppendKeyValue("env", "node")
   361  
   362  				index, action := policyDB.Search(tags)
   363  				So(index, ShouldEqual, -1)
   364  				So(action, ShouldBeNil)
   365  			})
   366  
   367  			Convey("Given that I search for a single that succeeds in the Not Key  operator, it should succeed ,", func() {
   368  				tags := policy.NewTagStore()
   369  				tags.AppendKeyValue("app", "web")
   370  
   371  				index, action := policyDB.Search(tags)
   372  				So(index, ShouldEqual, index6)
   373  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   374  			})
   375  
   376  			Convey("Given that I search for a value that matches a prefix", func() {
   377  				tags := policy.NewTagStore()
   378  				tags.AppendKeyValue("domain", "com.example.db")
   379  				index, action := policyDB.Search(tags)
   380  				So(index, ShouldEqual, index7)
   381  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   382  			})
   383  
   384  			Convey("Given that I search for a value that matches a complete value ", func() {
   385  				tags := policy.NewTagStore()
   386  				tags.AppendKeyValue("domain", "com.example.web")
   387  
   388  				index, action := policyDB.Search(tags)
   389  				So(index, ShouldEqual, index8)
   390  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   391  			})
   392  
   393  			Convey("Given that I search for a value that matches some of the prefix, it should return err  ", func() {
   394  				tags := policy.NewTagStore()
   395  				tags.AppendKeyValue("domain", "co")
   396  				tags.AppendKeyValue("env", "node")
   397  
   398  				index, action := policyDB.Search(tags)
   399  				So(index, ShouldEqual, -1)
   400  				So(action, ShouldBeNil)
   401  			})
   402  
   403  			Convey("Given that I search for a value matches only the env not exists policy ", func() {
   404  				tags := policy.NewTagStore()
   405  				tags.AppendKeyValue("sometag", "nomatch")
   406  
   407  				index, action := policyDB.Search(tags)
   408  				So(index, ShouldEqual, index9)
   409  				So(action.(*policy.FlowPolicy).Action, ShouldEqual, policy.Accept)
   410  			})
   411  
   412  		})
   413  
   414  	})
   415  }
   416  
   417  // TestFuncDumbDB is a mock test for the print function
   418  func TestFuncDumpDB(t *testing.T) {
   419  	Convey("Given an empty policy DB", t, func() {
   420  		policyDB := NewPolicyDB()
   421  
   422  		Convey("Given that I add two policy rules, I should be able to print the db ", func() {
   423  			index1 := policyDB.AddPolicy(appEqWebAndenvEqDemo)
   424  			index2 := policyDB.AddPolicy(policylangNotJava)
   425  			So(index1, ShouldEqual, 1)
   426  			So(index2, ShouldEqual, 2)
   427  
   428  			policyDB.PrintPolicyDB()
   429  
   430  		})
   431  	})
   432  }