...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/rules/rules_test.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/rules

     1  package rulesengine
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  var commandNames = []Command{
    12  	{Name: "a"},
    13  	{Name: "b"},
    14  	{Name: "c"},
    15  }
    16  
    17  var privilegeNames = []Privilege{
    18  	{Name: "a"},
    19  	{Name: "b"},
    20  	{Name: "c"},
    21  }
    22  
    23  func TestSplitPostDefaultRulesToRuleSegment(t *testing.T) {
    24  	t.Parallel()
    25  
    26  	tests := map[string]struct {
    27  		rules WriteRules
    28  		exp   []RuleSegment
    29  	}{
    30  		"One Rule": {
    31  			rules: WriteRules{
    32  				{
    33  					Command:    commandNames[0].Name,
    34  					Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name},
    35  				},
    36  			},
    37  			exp: []RuleSegment{
    38  				{Command: commandNames[0], Privilege: privilegeNames[0]},
    39  				{Command: commandNames[0], Privilege: privilegeNames[1]},
    40  			},
    41  		},
    42  		"Multiple Rules": {
    43  			rules: WriteRules{
    44  				{
    45  					Command:    commandNames[0].Name,
    46  					Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name},
    47  				},
    48  				{
    49  					Command:    commandNames[1].Name,
    50  					Privileges: []string{privilegeNames[1].Name, privilegeNames[2].Name},
    51  				},
    52  				{
    53  					Command:    commandNames[2].Name,
    54  					Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name, privilegeNames[2].Name},
    55  				},
    56  			},
    57  			exp: []RuleSegment{
    58  				{Command: commandNames[0], Privilege: privilegeNames[0]},
    59  				{Command: commandNames[0], Privilege: privilegeNames[1]},
    60  				{Command: commandNames[1], Privilege: privilegeNames[1]},
    61  				{Command: commandNames[1], Privilege: privilegeNames[2]},
    62  				{Command: commandNames[2], Privilege: privilegeNames[0]},
    63  				{Command: commandNames[2], Privilege: privilegeNames[1]},
    64  				{Command: commandNames[2], Privilege: privilegeNames[2]},
    65  			},
    66  		},
    67  	}
    68  
    69  	for name, tc := range tests {
    70  		tc := tc
    71  		t.Run(name, func(t *testing.T) {
    72  			t.Parallel()
    73  
    74  			segments := splitPostDefaultRulesToRuleSegment(tc.rules)
    75  			assert.Equal(t, tc.exp, segments)
    76  		})
    77  	}
    78  }
    79  
    80  func TestAssembleRules(t *testing.T) {
    81  	tests := map[string]struct {
    82  		ruleSegments []RuleSegment
    83  		expectedRes  []Rule
    84  	}{
    85  		"2 privs 2 commands": {
    86  			ruleSegments: []RuleSegment{
    87  				{
    88  					Command: Command{
    89  						Name: "com1",
    90  						ID:   "comID1"},
    91  					Privilege: Privilege{
    92  						Name: "priv1",
    93  						ID:   "privID1",
    94  					},
    95  				},
    96  				{
    97  					Command: Command{
    98  						Name: "com1",
    99  						ID:   "comID1"},
   100  					Privilege: Privilege{
   101  						Name: "priv2",
   102  						ID:   "privID2",
   103  					},
   104  				},
   105  				{
   106  					Command: Command{
   107  						Name: "com2",
   108  						ID:   "comID2"},
   109  					Privilege: Privilege{
   110  						Name: "priv3",
   111  						ID:   "privID3",
   112  					},
   113  				},
   114  			},
   115  			expectedRes: []Rule{
   116  				{
   117  					Command:    Command{Name: "com1", ID: "comID1"},
   118  					Privileges: []Privilege{{Name: "priv1", ID: "privID1"}, {Name: "priv2", ID: "privID2"}},
   119  				},
   120  				{
   121  					Command:    Command{Name: "com2", ID: "comID2"},
   122  					Privileges: []Privilege{{Name: "priv3", ID: "privID3"}},
   123  				},
   124  			},
   125  		},
   126  		"Banner ignored": {
   127  			ruleSegments: []RuleSegment{
   128  				{
   129  					Banner: Banner{BannerName: "bannername", BannerID: "bannerID"},
   130  					Command: Command{
   131  						Name: "com1",
   132  						ID:   "comID1"},
   133  					Privilege: Privilege{
   134  						Name: "priv1",
   135  						ID:   "privID1",
   136  					},
   137  				},
   138  			},
   139  			expectedRes: []Rule{
   140  				{
   141  					Command:    Command{Name: "com1", ID: "comID1"},
   142  					Privileges: []Privilege{{Name: "priv1", ID: "privID1"}},
   143  				}},
   144  		},
   145  	}
   146  	for name, tc := range tests {
   147  		t.Run(name, func(t *testing.T) {
   148  			assert.EqualValues(t, tc.expectedRes, assembleRules(tc.ruleSegments))
   149  		})
   150  	}
   151  }
   152  
   153  type mockDefaultRulesDS struct {
   154  	addDefaultRulesFunc  func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error)
   155  	readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error)
   156  	Dataset
   157  }
   158  
   159  func (m *mockDefaultRulesDS) AddDefaultRules(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) {
   160  	if m.addDefaultRulesFunc != nil {
   161  		return m.addDefaultRulesFunc(ctx, ruleSegments)
   162  	}
   163  	return AddRuleResult{}, fmt.Errorf("AddDefaultRules not implemented")
   164  }
   165  
   166  func (m *mockDefaultRulesDS) ReadAllDefaultRules(ctx context.Context) ([]RuleSegment, error) {
   167  	if m.readDefaultRulesFunc != nil {
   168  		return m.readDefaultRulesFunc(ctx)
   169  	}
   170  	return nil, fmt.Errorf("ReadDefaultRules not implemented")
   171  }
   172  
   173  func newMockDefaultRulesDS(addDefaultRulesFunc func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error),
   174  	readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error)) *mockDefaultRulesDS {
   175  	return &mockDefaultRulesDS{
   176  		addDefaultRulesFunc:  addDefaultRulesFunc,
   177  		readDefaultRulesFunc: readDefaultRulesFunc,
   178  	}
   179  }
   180  
   181  type helper interface {
   182  	Helper()
   183  }
   184  
   185  func ErrorEqualMsg(message string) assert.ErrorAssertionFunc {
   186  	return func(t assert.TestingT, err error, i ...interface{}) bool {
   187  		if tt, ok := t.(helper); ok {
   188  			tt.Helper()
   189  		}
   190  
   191  		return assert.EqualError(t, err, message, i...)
   192  	}
   193  }
   194  
   195  func TestAddDefaultRulesForPrivileges(t *testing.T) {
   196  	t.Parallel()
   197  	tests := map[string]struct {
   198  		data          []RuleSet
   199  		expectedRules []RuleSegment
   200  		assertErr     assert.ErrorAssertionFunc
   201  	}{
   202  		"Single Privilege, Single Command": {
   203  			data: []RuleSet{
   204  				{
   205  					Privilege: "privilege1",
   206  					Commands:  []string{"command1"},
   207  				},
   208  			},
   209  			expectedRules: []RuleSegment{
   210  				{
   211  					Command:   Command{Name: "command1"},
   212  					Privilege: Privilege{Name: "privilege1"},
   213  				},
   214  			},
   215  			assertErr: assert.NoError,
   216  		},
   217  		"Single Privilege, Multiple Commands": {
   218  			data: []RuleSet{
   219  				{
   220  					Privilege: "privilege1",
   221  					Commands:  []string{"command1", "command2"},
   222  				},
   223  			},
   224  			expectedRules: []RuleSegment{
   225  				{
   226  					Command:   Command{Name: "command1"},
   227  					Privilege: Privilege{Name: "privilege1"},
   228  				},
   229  				{
   230  					Command:   Command{Name: "command2"},
   231  					Privilege: Privilege{Name: "privilege1"},
   232  				},
   233  			},
   234  			assertErr: assert.NoError,
   235  		},
   236  		"Multiple Privileges, Single Command": {
   237  			data: []RuleSet{
   238  				{
   239  					Privilege: "privilege1",
   240  					Commands:  []string{"command1"},
   241  				},
   242  				{
   243  					Privilege: "privilege2",
   244  					Commands:  []string{"command1"},
   245  				},
   246  			},
   247  			expectedRules: []RuleSegment{
   248  				{
   249  					Command:   Command{Name: "command1"},
   250  					Privilege: Privilege{Name: "privilege1"},
   251  				},
   252  				{
   253  					Command:   Command{Name: "command1"},
   254  					Privilege: Privilege{Name: "privilege2"},
   255  				},
   256  			},
   257  			assertErr: assert.NoError,
   258  		},
   259  		"Multiple Privileges, Multiple Commands": {
   260  			data: []RuleSet{
   261  				{
   262  					Privilege: "privilege1",
   263  					Commands:  []string{"command1", "command2"},
   264  				},
   265  				{
   266  					Privilege: "privilege2",
   267  					Commands:  []string{"command3"},
   268  				},
   269  			},
   270  			expectedRules: []RuleSegment{
   271  				{
   272  					Command:   Command{Name: "command1"},
   273  					Privilege: Privilege{Name: "privilege1"},
   274  				},
   275  				{
   276  					Command:   Command{Name: "command2"},
   277  					Privilege: Privilege{Name: "privilege1"},
   278  				},
   279  				{
   280  					Command:   Command{Name: "command3"},
   281  					Privilege: Privilege{Name: "privilege2"},
   282  				},
   283  			},
   284  			assertErr: assert.NoError,
   285  		},
   286  		"No Privileges": {
   287  			data:          []RuleSet{},
   288  			expectedRules: []RuleSegment{},
   289  			assertErr:     ErrorEqualMsg("empty rules list"),
   290  		},
   291  	}
   292  
   293  	for name, tc := range tests {
   294  		tc := tc
   295  		t.Run(name, func(t *testing.T) {
   296  			t.Parallel()
   297  			ctx := context.Background()
   298  
   299  			// Create an instance of the RulesEngine
   300  			reng := RulesEngine{}
   301  
   302  			// Set up a mock ds
   303  			reng.ds = newMockDefaultRulesDS(func(_ context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) {
   304  				// test the rulesegments match the expected rules
   305  				assert.ElementsMatch(t, tc.expectedRules, ruleSegments)
   306  				return AddRuleResult{}, nil
   307  			}, nil)
   308  
   309  			// Call the AddDefaultRulesFromData function
   310  			_, err := reng.AddDefaultRulesForPrivileges(ctx, tc.data)
   311  
   312  			// check the error
   313  			tc.assertErr(t, err)
   314  		})
   315  	}
   316  }
   317  
   318  func TestGetDefaultRules(t *testing.T) {
   319  	t.Parallel()
   320  	tests := map[string]struct {
   321  		privilegeNames []string
   322  		defaultRules   []RuleSegment
   323  		expectedRules  []ReturnRuleSet
   324  		expectedErr    error
   325  	}{
   326  		"Existing Privilege": {
   327  			privilegeNames: []string{"privilege1"},
   328  			defaultRules: []RuleSegment{
   329  				{
   330  					Command:   Command{Name: "command1", ID: "commandID1"},
   331  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   332  				},
   333  				{
   334  					Command:   Command{Name: "command2", ID: "commandID2"},
   335  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   336  				},
   337  			},
   338  			expectedRules: []ReturnRuleSet{
   339  				{
   340  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   341  					Commands: []Command{
   342  						{Name: "command1", ID: "commandID1"},
   343  						{Name: "command2", ID: "commandID2"},
   344  					},
   345  				},
   346  			},
   347  			expectedErr: nil,
   348  		},
   349  		"Non-Existing Privilege": {
   350  			privilegeNames: []string{"privilege2"},
   351  			defaultRules: []RuleSegment{
   352  				{
   353  					Command:   Command{Name: "command1", ID: "commandID1"},
   354  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   355  				},
   356  				{
   357  					Command:   Command{Name: "command2", ID: "commandID2"},
   358  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   359  				},
   360  			},
   361  			expectedRules: []ReturnRuleSet{},
   362  			expectedErr:   nil,
   363  		},
   364  		"Empty Default Rules": {
   365  			privilegeNames: []string{"privilege1"},
   366  			defaultRules:   []RuleSegment{},
   367  			expectedRules:  []ReturnRuleSet{},
   368  			expectedErr:    nil,
   369  		},
   370  		"Error Reading Default Rules": {
   371  			privilegeNames: []string{"privilege1"},
   372  			defaultRules:   nil,
   373  			expectedRules:  []ReturnRuleSet{},
   374  			expectedErr:    fmt.Errorf("error when reading all default rules: some error"),
   375  		},
   376  		"No Privilege Names": {
   377  			privilegeNames: []string{},
   378  			defaultRules: []RuleSegment{
   379  				{
   380  					Command:   Command{Name: "command1", ID: "commandID1"},
   381  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   382  				},
   383  				{
   384  					Command:   Command{Name: "command2", ID: "commandID2"},
   385  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   386  				},
   387  			},
   388  			expectedRules: []ReturnRuleSet{
   389  				{
   390  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   391  					Commands: []Command{
   392  						{Name: "command1", ID: "commandID1"},
   393  						{Name: "command2", ID: "commandID2"},
   394  					},
   395  				},
   396  			},
   397  			expectedErr: nil,
   398  		},
   399  		"Multiple privilege Names": {
   400  			privilegeNames: []string{"privilege1", "privilege2"},
   401  			defaultRules: []RuleSegment{
   402  				{
   403  					Command:   Command{Name: "command1", ID: "commandID1"},
   404  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   405  				},
   406  				{
   407  					Command:   Command{Name: "command2", ID: "commandID2"},
   408  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   409  				},
   410  				{
   411  					Command:   Command{Name: "command3", ID: "commandID3"},
   412  					Privilege: Privilege{Name: "privilege2", ID: "privID2"},
   413  				},
   414  			},
   415  			expectedRules: []ReturnRuleSet{
   416  				{
   417  					Privilege: Privilege{Name: "privilege1", ID: "privID1"},
   418  					Commands: []Command{
   419  						{Name: "command1", ID: "commandID1"},
   420  						{Name: "command2", ID: "commandID2"}},
   421  				},
   422  				{
   423  					Privilege: Privilege{Name: "privilege2", ID: "privID2"},
   424  					Commands:  []Command{{Name: "command3", ID: "commandID3"}},
   425  				},
   426  			},
   427  			expectedErr: nil,
   428  		},
   429  	}
   430  
   431  	for name, tc := range tests {
   432  		tc := tc
   433  		t.Run(name, func(t *testing.T) {
   434  			t.Parallel()
   435  			ctx := context.Background()
   436  			reng := RulesEngine{}
   437  			// Set up a mock ds
   438  			reng.ds = newMockDefaultRulesDS(nil, func(_ context.Context) ([]RuleSegment, error) {
   439  				return tc.defaultRules, tc.expectedErr
   440  			})
   441  			// Call the GetDefaultRules function
   442  			rules, err := reng.GetDefaultRules(ctx, tc.privilegeNames...)
   443  
   444  			// Test the result and error
   445  			assert.EqualValues(t, tc.expectedRules, rules)
   446  			assert.Equal(t, tc.expectedErr, err)
   447  		})
   448  	}
   449  }
   450  
   451  func TestAddDefaultRules(t *testing.T) {
   452  	t.Parallel()
   453  
   454  	tests := map[string]struct {
   455  		rules     WriteRules
   456  		assertErr assert.ErrorAssertionFunc
   457  	}{
   458  		"Empty rules": {
   459  			rules:     WriteRules{},
   460  			assertErr: ErrorEqualMsg("empty rules list"),
   461  		},
   462  		"Valid rules": {
   463  			rules: WriteRules{
   464  				{
   465  					Command:    "command1",
   466  					Privileges: []string{"privilege1", "privilege2"},
   467  				},
   468  				{
   469  					Command:    "command2",
   470  					Privileges: []string{"privilege1"},
   471  				},
   472  			},
   473  			assertErr: assert.NoError,
   474  		},
   475  		"Invalid command": {
   476  			rules: WriteRules{
   477  				{
   478  					Command:    "",
   479  					Privileges: []string{"privilege1", "privilege2"},
   480  				},
   481  			},
   482  			assertErr: ErrorEqualMsg("invalid rule at 0: empty command name"),
   483  		},
   484  		"Invalid privilege": {
   485  			rules: WriteRules{
   486  				{
   487  					Command:    "command1",
   488  					Privileges: []string{""},
   489  				},
   490  			},
   491  			assertErr: ErrorEqualMsg("invalid rule at 0: empty privilege name in array at 0"),
   492  		},
   493  	}
   494  
   495  	for name, tc := range tests {
   496  		tc := tc
   497  		t.Run(name, func(t *testing.T) {
   498  			t.Parallel()
   499  
   500  			ctx := context.Background()
   501  			reng := RulesEngine{}
   502  			// Set up a mock ds
   503  			reng.ds = newMockDefaultRulesDS(func(_ context.Context, _ []RuleSegment) (AddRuleResult, error) {
   504  				return AddRuleResult{}, nil
   505  			},
   506  				nil)
   507  
   508  			_, err := reng.AddDefaultRules(ctx, tc.rules)
   509  			tc.assertErr(t, err)
   510  		})
   511  	}
   512  }
   513  

View as plain text