1 package rulesengine
2
3 import (
4 "context"
5 "fmt"
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 )
10
11 var banners = []Banner{{
12 BannerID: "a",
13 BannerName: "b",
14 }, {
15 BannerID: "c",
16 BannerName: "d",
17 }, {
18 BannerID: "e",
19 BannerName: "f",
20 },
21 }
22
23 var commands = []Command{{
24 ID: "a",
25 Name: "b",
26 }, {
27 ID: "c",
28 Name: "d",
29 }, {
30 ID: "e",
31 Name: "f",
32 },
33 }
34
35 var privileges = []Privilege{{
36 ID: "a",
37 Name: "b",
38 }, {
39 ID: "c",
40 Name: "d",
41 }, {
42 ID: "e",
43 Name: "f",
44 },
45 }
46
47 func TestAssembleGetBannerRule(t *testing.T) {
48 t.Parallel()
49
50 tests := map[string]struct {
51 in []RuleSegment
52 out []ReadBannerRule
53 err error
54 }{
55 "simple": {
56 in: []RuleSegment{
57 {
58 Banner: banners[0],
59 Command: commands[0],
60 Privilege: privileges[0],
61 },
62 },
63 out: []ReadBannerRule{
64 {
65 Command: commands[0],
66 Banners: []BannerPrivOverrides{
67 {
68 Banner: banners[0],
69 Privileges: []Privilege{
70 privileges[0],
71 },
72 },
73 },
74 },
75 },
76 },
77 "Two Banners": {
78 in: []RuleSegment{
79 {
80 Banner: banners[0],
81 Command: commands[0],
82 Privilege: privileges[0],
83 },
84 {
85 Banner: banners[1],
86 Command: commands[0],
87 Privilege: privileges[0],
88 },
89 },
90 out: []ReadBannerRule{
91 {
92 Command: commands[0],
93 Banners: []BannerPrivOverrides{
94 {
95 Banner: banners[0],
96 Privileges: []Privilege{
97 privileges[0],
98 },
99 },
100 {
101 Banner: banners[1],
102 Privileges: []Privilege{
103 privileges[0],
104 },
105 },
106 },
107 },
108 },
109 },
110 "Two Privileges": {
111 in: []RuleSegment{
112 {
113 Banner: banners[0],
114 Command: commands[0],
115 Privilege: privileges[0],
116 },
117 {
118 Banner: banners[0],
119 Command: commands[0],
120 Privilege: privileges[1],
121 },
122 },
123 out: []ReadBannerRule{
124 {
125 Command: commands[0],
126 Banners: []BannerPrivOverrides{
127 {
128 Banner: banners[0],
129 Privileges: []Privilege{
130 privileges[0],
131 privileges[1],
132 },
133 },
134 },
135 },
136 },
137 },
138 "Two commands": {
139 in: []RuleSegment{
140 {
141 Banner: banners[0],
142 Command: commands[0],
143 Privilege: privileges[0],
144 },
145 {
146 Banner: banners[0],
147 Command: commands[1],
148 Privilege: privileges[0],
149 },
150 },
151 out: []ReadBannerRule{
152 {
153 Command: commands[0],
154 Banners: []BannerPrivOverrides{
155 {
156 Banner: banners[0],
157 Privileges: []Privilege{
158 privileges[0],
159 },
160 },
161 },
162 },
163 {
164 Command: commands[1],
165 Banners: []BannerPrivOverrides{
166 {
167 Banner: banners[0],
168 Privileges: []Privilege{
169 privileges[0],
170 },
171 },
172 },
173 },
174 },
175 },
176 "No banner": {
177 in: []RuleSegment{
178 {
179 Command: commands[0],
180 Privilege: privileges[0],
181 },
182 },
183 err: fmt.Errorf("error in assembeGetBannerRule: Banner was nil"),
184 },
185 }
186
187 for name, tc := range tests {
188 tc := tc
189 t.Run(name, func(t *testing.T) {
190 t.Parallel()
191 res, err := assembleGetBannerRule(tc.in)
192 assert.Equal(t, tc.err, err)
193 assert.Equal(t, tc.out, res)
194 })
195 }
196 }
197
198 type MockDS struct {
199 funcResults map[string]any
200 funcErrors map[string]error
201 Dataset
202 }
203
204 func newMockDS(res map[string]any, errs map[string]error) MockDS {
205 return MockDS{funcResults: res, funcErrors: errs}
206 }
207
208 func (mds MockDS) ReadDefaultRulesForCommand(_ context.Context, _ string) (rules []RuleSegment, err error) {
209 res, ok := mds.funcResults["ReadDefaultRulesForCommand"].([]RuleSegment)
210 if !ok {
211 return rules, fmt.Errorf("key not found in funcResults or incorrect type")
212 }
213 err, ok = mds.funcErrors["ReadDefaultRulesForCommand"]
214 if !ok {
215 return rules, fmt.Errorf("key not found in funcErrors")
216 }
217 return res, err
218 }
219
220
221 func (mds MockDS) ReadBannerRulesForCommand(_ context.Context, _ string) (rules []RuleSegment, err error) {
222 res, ok := mds.funcResults["ReadBannerRulesForCommand"].([]RuleSegment)
223 if !ok {
224 return rules, fmt.Errorf("key not found in funcResults or incorrect type")
225 }
226 err, ok = mds.funcErrors["ReadBannerRulesForCommand"]
227 if !ok {
228 return rules, fmt.Errorf("key not found in funcErrors")
229 }
230 return res, err
231 }
232
233 func (mds MockDS) ReadCommand(_ context.Context, _ string) (command Command, err error) {
234 res, ok := mds.funcResults["ReadCommand"].(Command)
235 if !ok {
236 return command, fmt.Errorf("key not found in funcResults or incorrect type")
237 }
238 err, ok = mds.funcErrors["ReadCommand"]
239 if !ok {
240 return command, fmt.Errorf("key not found in funcErrors")
241 }
242 return res, err
243 }
244
245 var (
246 testBannerRuleSegment = []RuleSegment{
247 {
248 Banner: Banner{
249 BannerName: "testBanner",
250 BannerID: "testBannerID",
251 },
252 Command: Command{
253 Name: "testCommand",
254 ID: "testComID",
255 },
256 Privilege: Privilege{
257 Name: "testPrivilege",
258 ID: "testPrivID",
259 },
260 },
261 }
262 testDefaultRuleSegment = []RuleSegment{{
263 Command: Command{
264 Name: "testCommand",
265 ID: "testComID",
266 },
267 Privilege: Privilege{
268 Name: "testPrivilege",
269 ID: "testPrivID",
270 },
271 }}
272 )
273
274 func TestReadAllRulesForCommand(t *testing.T) {
275 t.Parallel()
276 tests := map[string]struct {
277 funcResults map[string]interface{}
278 funcErrors map[string]error
279 finalError error
280 expectedRes RuleWithOverrides
281 }{
282 "No errors": {
283 funcResults: map[string]interface{}{
284 "ReadBannerRulesForCommand": testBannerRuleSegment,
285 "ReadDefaultRulesForCommand": testDefaultRuleSegment,
286 },
287 funcErrors: map[string]error{
288 "ReadBannerRulesForCommand": nil,
289 "ReadDefaultRulesForCommand": nil,
290 },
291 finalError: nil,
292 expectedRes: RuleWithOverrides{
293 Command: Command{
294
295 Name: "testCommand",
296 ID: "testComID",
297 },
298 Banners: []BannerPrivOverrides{{
299 Privileges: []Privilege{{
300 Name: "testPrivilege",
301 ID: "testPrivID",
302 },
303 },
304 Banner: Banner{
305 BannerName: "testBanner",
306 BannerID: "testBannerID",
307 },
308 },
309 },
310 Default: DefaultRule{Privileges: []Privilege{testDefaultRuleSegment[0].Privilege}},
311 },
312 },
313 "Error with ReadBannerRulesForCommand": {
314 funcResults: map[string]interface{}{
315 "ReadBannerRulesForCommand": testBannerRuleSegment,
316 "ReadDefaultRulesForCommand": testDefaultRuleSegment,
317 },
318 funcErrors: map[string]error{
319 "ReadBannerRulesForCommand": fmt.Errorf("an error occurred in ReadBannerRulesForCommand"),
320 "ReadDefaultRulesForCommand": nil,
321 },
322 finalError: fmt.Errorf("error finding banner rules: error querying for rules: an error occurred in ReadBannerRulesForCommand"),
323 },
324 "Error with ReadDefaultRulesForCommand": {
325 funcResults: map[string]interface{}{
326 "ReadBannerRulesForCommand": testBannerRuleSegment,
327 "ReadDefaultRulesForCommand": testDefaultRuleSegment,
328 },
329 funcErrors: map[string]error{
330 "ReadBannerRulesForCommand": nil,
331 "ReadDefaultRulesForCommand": fmt.Errorf("an error occurred in ReadRulesDefaultRulesForCommand"),
332 },
333 finalError: fmt.Errorf("error finding default rules: an error occurred in ReadRulesDefaultRulesForCommand"),
334 },
335 "No command in database": {
336 funcResults: map[string]interface{}{
337 "ReadDefaultRulesForCommand": []RuleSegment(nil),
338 "ReadBannerRulesForCommand": []RuleSegment(nil),
339 "ReadCommand": Command{},
340 },
341 funcErrors: map[string]error{
342 "ReadDefaultRulesForCommand": nil,
343 "ReadBannerRulesForCommand": nil,
344 "ReadCommand": nil,
345 },
346 expectedRes: RuleWithOverrides{},
347 },
348 "No Banner command": {
349 funcResults: map[string]interface{}{
350 "ReadBannerRulesForCommand": []RuleSegment{},
351 "ReadDefaultRulesForCommand": testDefaultRuleSegment,
352 },
353 funcErrors: map[string]error{
354 "ReadBannerRulesForCommand": nil,
355 "ReadDefaultRulesForCommand": nil,
356 },
357 finalError: nil,
358 expectedRes: RuleWithOverrides{
359 Command: Command{
360 Name: "testCommand",
361 ID: "testComID",
362 },
363 Banners: []BannerPrivOverrides{},
364 Default: DefaultRule{Privileges: []Privilege{testDefaultRuleSegment[0].Privilege}},
365 },
366 },
367 "No default command": {
368 funcResults: map[string]interface{}{
369 "ReadBannerRulesForCommand": testBannerRuleSegment,
370 "ReadDefaultRulesForCommand": []RuleSegment{},
371 },
372 funcErrors: map[string]error{
373 "ReadBannerRulesForCommand": nil,
374 "ReadDefaultRulesForCommand": nil,
375 },
376 finalError: nil,
377 expectedRes: RuleWithOverrides{
378 Command: Command{
379 Name: "testCommand",
380 ID: "testComID",
381 },
382 Banners: []BannerPrivOverrides{{
383 Privileges: []Privilege{{
384 Name: "testPrivilege",
385 ID: "testPrivID",
386 }},
387 Banner: Banner{
388 BannerName: "testBanner",
389 BannerID: "testBannerID",
390 },
391 }},
392 },
393 },
394 }
395
396 for name, tc := range tests {
397 tc := tc
398 t.Run(name, func(t *testing.T) {
399 t.Parallel()
400
401 mds := newMockDS(tc.funcResults, tc.funcErrors)
402 reng := RulesEngine{}
403 reng.ds = mds
404 res, err := reng.ReadAllRulesForCommand(context.Background(), "testCommand")
405
406 assert.Equal(t, tc.finalError, err)
407 if err == nil && tc.finalError == nil {
408 assert.EqualValues(t, tc.expectedRes, res)
409 }
410 })
411 }
412 }
413
414 func TestSplitPostRulesToBannerSegment(t *testing.T) {
415 t.Parallel()
416
417 tests := map[string]struct {
418 inputBanner string
419 inputRules []WriteRule
420 expOut []RuleSegment
421 }{
422 "simple": {
423 inputBanner: "myBanner",
424 inputRules: []WriteRule{
425 {Command: "ls", Privileges: []string{"read"}},
426 },
427 expOut: []RuleSegment{
428 {Banner: Banner{BannerName: "myBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "read"}},
429 },
430 },
431 "Multiple command": {
432 inputBanner: "myBanner",
433 inputRules: []WriteRule{
434 {Command: "ls", Privileges: []string{"read"}},
435 {Command: "cat", Privileges: []string{"read"}},
436 },
437 expOut: []RuleSegment{
438 {Banner: Banner{BannerName: "myBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "read"}},
439 {Banner: Banner{BannerName: "myBanner"}, Command: Command{Name: "cat"}, Privilege: Privilege{Name: "read"}},
440 },
441 },
442 "Multiple Privileges": {
443 inputBanner: "myBanner",
444 inputRules: []WriteRule{
445 {Command: "ls", Privileges: []string{"read", "write"}},
446 },
447 expOut: []RuleSegment{
448 {Banner: Banner{BannerName: "myBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "read"}},
449 {Banner: Banner{BannerName: "myBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "write"}},
450 },
451 },
452 "Multiple Everything": {
453 inputBanner: "aBanner",
454 inputRules: []WriteRule{
455 {Command: "ls", Privileges: []string{"read", "write"}},
456 {Command: "cat", Privileges: []string{"read", "readOnly"}},
457 },
458 expOut: []RuleSegment{
459 {Banner: Banner{BannerName: "aBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "read"}},
460 {Banner: Banner{BannerName: "aBanner"}, Command: Command{Name: "ls"}, Privilege: Privilege{Name: "write"}},
461 {Banner: Banner{BannerName: "aBanner"}, Command: Command{Name: "cat"}, Privilege: Privilege{Name: "read"}},
462 {Banner: Banner{BannerName: "aBanner"}, Command: Command{Name: "cat"}, Privilege: Privilege{Name: "readOnly"}},
463 },
464 },
465 }
466
467 for name, tc := range tests {
468 name := name
469 tc := tc
470 t.Run(name, func(t *testing.T) {
471 t.Parallel()
472
473 out := splitPostRulesToBannerSegment(tc.inputBanner, tc.inputRules)
474
475 assert.Equal(t, tc.expOut, out)
476 })
477 }
478 }
479
480 type readBannerRulesForCommandAndBannerMock struct {
481 Dataset
482
483 commandName string
484 bannerName string
485 retOut []RuleSegment
486 retErr error
487 }
488 type readBannerRulesForCommandMock struct {
489 Dataset
490
491 commandName string
492 retOut []RuleSegment
493 retErr error
494 }
495
496 func (m *readBannerRulesForCommandMock) ReadBannerRulesForCommand(_ context.Context, commandName string) ([]RuleSegment, error) {
497 m.commandName = commandName
498
499 return m.retOut, m.retErr
500 }
501
502 func TestReadBannerRulesForCommand(t *testing.T) {
503 t.Parallel()
504
505 tests := map[string]struct {
506 commandName string
507
508 retOut []RuleSegment
509 retErr error
510
511 expOut ReadBannerRule
512 expErr assert.ErrorAssertionFunc
513 }{
514 "Standard": {
515 commandName: "ls",
516 retOut: []RuleSegment{
517 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
518 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-write", ID: "e"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
519 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner2", BannerID: "d"}},
520 },
521 retErr: nil,
522
523 expOut: ReadBannerRule{
524 Command: Command{Name: "ls", ID: "a"},
525 Banners: []BannerPrivOverrides{
526 {
527 Banner: Banner{BannerName: "myBanner", BannerID: "c"},
528 Privileges: []Privilege{
529 {Name: "ea-read", ID: "b"},
530 {Name: "ea-write", ID: "e"},
531 },
532 },
533 {
534 Banner: Banner{BannerName: "myBanner2", BannerID: "d"},
535 Privileges: []Privilege{
536 {Name: "ea-read", ID: "b"},
537 },
538 },
539 },
540 },
541 expErr: assert.NoError,
542 },
543 "No output": {
544 commandName: "cat",
545 retOut: nil,
546 retErr: nil,
547 expOut: ReadBannerRule{},
548 expErr: assert.NoError,
549 },
550 "Error": {
551 commandName: "ls",
552 retOut: nil,
553 retErr: fmt.Errorf("an error"),
554 expOut: ReadBannerRule{},
555 expErr: assert.Error,
556 },
557 "Too Many commands returned": {
558 commandName: "ls",
559 retOut: []RuleSegment{
560 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
561 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-write", ID: "e"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
562 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner2", BannerID: "d"}},
563 {Command: Command{Name: "cat", ID: "b"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
564 },
565 retErr: nil,
566 expOut: ReadBannerRule{},
567 expErr: assert.Error,
568 },
569 }
570
571 for name, tc := range tests {
572 tc := tc
573 t.Run(name, func(t *testing.T) {
574 t.Parallel()
575
576 ds := readBannerRulesForCommandMock{
577 retOut: tc.retOut,
578 retErr: tc.retErr,
579 }
580
581 re := New(&ds)
582
583 out, err := re.ReadBannerRulesForCommand(context.Background(), tc.commandName)
584
585 assert.Equal(t, tc.commandName, ds.commandName)
586 assert.Equal(t, tc.expOut, out)
587 tc.expErr(t, err)
588 })
589 }
590 }
591
592 func (m *readBannerRulesForCommandAndBannerMock) ReadBannerRulesForCommandAndBanner(_ context.Context, bannerName string, commandName string) ([]RuleSegment, error) {
593 m.commandName = commandName
594 m.bannerName = bannerName
595
596 return m.retOut, m.retErr
597 }
598
599 func TestReadBannerRulesForCommandAndBanner(t *testing.T) {
600 t.Parallel()
601
602 tests := map[string]struct {
603 banneName string
604 commandName string
605
606 retOut []RuleSegment
607 retErr error
608
609 expOut Rule
610 expErr assert.ErrorAssertionFunc
611 }{
612 "Standard": {
613 banneName: "myBanner",
614 commandName: "ls",
615 retOut: []RuleSegment{
616 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}},
617 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-write", ID: "e"}},
618 },
619 retErr: nil,
620
621 expOut: Rule{
622 Command: Command{Name: "ls", ID: "a"},
623 Privileges: []Privilege{
624 {Name: "ea-read", ID: "b"},
625 {Name: "ea-write", ID: "e"},
626 },
627 },
628 expErr: assert.NoError,
629 },
630 "No output": {
631 banneName: "myBanner2",
632 commandName: "cat",
633 retOut: nil,
634 retErr: nil,
635 expOut: Rule{},
636 expErr: assert.NoError,
637 },
638 "Error": {
639 banneName: "myBanner",
640 commandName: "ls",
641 retOut: nil,
642 retErr: fmt.Errorf("an error"),
643 expOut: Rule{},
644 expErr: assert.Error,
645 },
646 "Too Many commands returned": {
647 banneName: "myBanner",
648 commandName: "ls",
649 retOut: []RuleSegment{
650 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
651 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-write", ID: "e"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
652 {Command: Command{Name: "ls", ID: "a"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner2", BannerID: "d"}},
653 {Command: Command{Name: "cat", ID: "b"}, Privilege: Privilege{Name: "ea-read", ID: "b"}, Banner: Banner{BannerName: "myBanner", BannerID: "c"}},
654 },
655 retErr: nil,
656 expOut: Rule{},
657 expErr: assert.Error,
658 },
659 }
660
661 for name, tc := range tests {
662 tc := tc
663 t.Run(name, func(t *testing.T) {
664 t.Parallel()
665
666 ds := readBannerRulesForCommandAndBannerMock{
667 retOut: tc.retOut,
668 retErr: tc.retErr,
669 }
670
671 re := New(&ds)
672
673 out, err := re.ReadBannerRulesForCommandAndBanner(context.Background(), tc.banneName, tc.commandName)
674
675 assert.Equal(t, tc.banneName, ds.bannerName)
676 assert.Equal(t, tc.commandName, ds.commandName)
677 assert.Equal(t, tc.expOut, out)
678 tc.expErr(t, err)
679 })
680 }
681 }
682
View as plain text