1 package rulestest
2
3 import (
4 "net/http"
5 "strings"
6 "testing"
7
8 "github.com/gin-gonic/gin"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11
12 _ "github.com/jackc/pgx/v4/stdlib"
13
14 "edge-infra.dev/test/f2"
15 "edge-infra.dev/test/f2/x/postgres"
16 )
17
18 const bannerData = `
19 INSERT INTO ea_rules_commands (command_id, name)
20 VALUES
21 ('78587bb1-6ca2-4d2d-a223-1ee642514b97', 'ls'),
22 ('eb6fc295-a46c-4407-a7a3-1438436d6aee', 'cat')
23 ;
24
25 INSERT INTO banners (banner_edge_id, banner_name)
26 VALUES
27 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', 'myBanner'),
28 ('8880dd52-f152-44ac-ac76-b37dd3a3a2f2', 'myBanner2')
29 ;
30
31 INSERT INTO ea_rules_privileges (privilege_id, name)
32 VALUES
33 ('a7c379ea-6e34-4017-8e86-eb545d7856a3', 'ea-read'),
34 ('caedabee-ea7a-4421-a608-ec04106e61da', 'ea-write')
35 ;
36 `
37
38 func TestAdminBannerRules(t *testing.T) {
39 var (
40 rulesEngine *gin.Engine
41 )
42
43 feat := f2.NewFeature("Admin Banner Rules").
44 Setup("Create Rules Engine server", func(ctx f2.Context, t *testing.T) f2.Context {
45 var db = postgres.FromContextT(ctx, t).DB()
46 rulesEngine, _ = setupRulesEngine(t, db)
47 return ctx
48 }).
49 Setup("Populate Seed Data", func(ctx f2.Context, t *testing.T) f2.Context {
50
51
52 var (
53 db = postgres.FromContextT(ctx, t).DB()
54 )
55
56 _, err := db.ExecContext(ctx, bannerData)
57 require.NoError(t, err)
58
59 return ctx
60 }).
61 Test("Get No Rules for Banner", func(ctx f2.Context, t *testing.T) f2.Context {
62 test := testCase{
63 url: "/admin/rules/banner/commands?bannerName=myBanner",
64 method: http.MethodGet,
65 expectedStatus: http.StatusOK,
66 expectedOut: `null`,
67 }
68
69 return testEndpoint(ctx, t, rulesEngine, test)
70 }).
71 Test("Get All Rules for non-existent banner", func(ctx f2.Context, t *testing.T) f2.Context {
72 test := testCase{
73 url: "/admin/rules/banner/commands?bannerName=nonExistentBanner",
74 method: http.MethodGet,
75 expectedStatus: http.StatusOK,
76 expectedOut: `null`,
77 }
78
79 return testEndpoint(ctx, t, rulesEngine, test)
80 }).
81 Test("Get All rules for Banner", func(ctx f2.Context, t *testing.T) f2.Context {
82
83 var (
84 db = postgres.FromContextT(ctx, t).DB()
85 )
86 _, err := db.ExecContext(ctx, `
87 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
88 VALUES
89 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3')
90 ;`,
91 )
92 assert.NoError(t, err)
93
94 test := testCase{
95 url: "/admin/rules/banner/commands?bannerName=myBanner",
96 method: http.MethodGet,
97 expectedStatus: http.StatusOK,
98 expectedOut: `[
99 {
100 "command": {
101 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97",
102 "name": "ls"
103 },
104 "privileges": [{
105 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3",
106 "name": "ea-read"
107 }]
108 }
109 ]`,
110 }
111
112 ctx = testEndpoint(ctx, t, rulesEngine, test)
113
114
115 _, err = db.ExecContext(ctx, `
116 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
117 VALUES
118 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da'),
119 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', 'eb6fc295-a46c-4407-a7a3-1438436d6aee', 'caedabee-ea7a-4421-a608-ec04106e61da')
120
121 ;`,
122 )
123 assert.NoError(t, err)
124
125 test.expectedOut = `[
126 {
127 "command": {
128 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97",
129 "name": "ls"
130 },
131 "privileges": [{
132 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3",
133 "name": "ea-read"
134 },
135 {
136 "id": "caedabee-ea7a-4421-a608-ec04106e61da",
137 "name": "ea-write"
138 }
139 ]
140 },
141 {
142 "command": {
143 "id": "eb6fc295-a46c-4407-a7a3-1438436d6aee",
144 "name": "cat"
145 },
146 "privileges": [{
147 "id": "caedabee-ea7a-4421-a608-ec04106e61da",
148 "name": "ea-write"
149 }]
150 }
151 ]`
152
153 ctx = testEndpoint(ctx, t, rulesEngine, test)
154
155 _, err = db.ExecContext(ctx, `DELETE from ea_rules;`)
156 assert.NoError(t, err)
157
158 return ctx
159 }).
160 Test("Get All Rules For All Banners", func(ctx f2.Context, t *testing.T) f2.Context {
161 var (
162 db = postgres.FromContextT(ctx, t).DB()
163 )
164
165 _, err := db.ExecContext(ctx, `
166 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
167 VALUES
168 ('8880dd52-f152-44ac-ac76-b37dd3a3a2f2', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3'),
169 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3')
170 ;`,
171 )
172 assert.NoError(t, err)
173
174 test := testCase{
175 url: "/admin/rules/banner/commands",
176 method: http.MethodGet,
177 expectedStatus: http.StatusOK,
178 expectedOut: `[
179 {
180 "command": {
181 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97",
182 "name": "ls"
183 },
184 "banners": [
185 {
186 "banner": {
187 "id": "8880dd52-f152-44ac-ac76-b37dd3a3a2f2",
188 "name": "myBanner2"
189 },
190 "privileges": [
191 {
192 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3",
193 "name":"ea-read"
194 }
195 ]
196 },
197 {
198 "banner": {
199 "id": "2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a",
200 "name": "myBanner"
201 },
202 "privileges": [
203 {
204 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3",
205 "name": "ea-read"
206 }
207 ]
208 }
209 ]
210 }
211 ]`,
212 }
213 ctx = testEndpoint(ctx, t, rulesEngine, test)
214
215 _, err = db.ExecContext(ctx, `DELETE from ea_rules;`)
216 assert.NoError(t, err)
217
218 return ctx
219 }).
220 Test("Delete Unknown Privilege From Rule in Banner", func(ctx f2.Context, t *testing.T) f2.Context {
221 test := testCase{
222 url: "/admin/rules/banner/commands/rm/privileges/read?bannerName=unknownBanner",
223 method: http.MethodDelete,
224 expectedStatus: http.StatusNotFound,
225 expectedOut: `{
226 "errors": [
227 {
228 "type": "Unknown Command",
229 "command":"rm"
230 },
231 {
232 "type":"Unknown Privilege",
233 "privilege":"read"
234 },
235 {
236 "type":"Unknown Banner",
237 "banner":"unknownBanner"
238 }
239 ]
240 }`,
241 }
242
243 return testEndpoint(ctx, t, rulesEngine, test)
244 }).
245 Test("Delete Known Privilege From No Rule in Banner", func(ctx f2.Context, t *testing.T) f2.Context {
246 test := testCase{
247 url: "/admin/rules/banner/commands/ls/privileges/ea-read?bannerName=myBanner",
248 method: http.MethodDelete,
249 expectedStatus: http.StatusNotFound,
250 expectedOut: `{
251 "errors": [{
252 "type": "Unknown Rule association",
253 "banner": "myBanner",
254 "command": "ls",
255 "privilege": "ea-read"
256 }]
257 }`,
258 }
259
260 return testEndpoint(ctx, t, rulesEngine, test)
261 }).
262 Test("Delete Known Privilege From Rule in Banner", func(ctx f2.Context, t *testing.T) f2.Context {
263 var (
264 db = postgres.FromContextT(ctx, t).DB()
265 )
266 _, err := db.ExecContext(ctx, `
267 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
268 VALUES
269 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3')
270 ;`,
271 )
272 assert.NoError(t, err)
273
274 test := testCase{
275 url: "/admin/rules/banner/commands/ls/privileges/ea-read?bannerName=myBanner",
276 method: http.MethodDelete,
277 expectedStatus: http.StatusOK,
278 expectedOut: ``,
279 }
280
281 ctx = testEndpoint(ctx, t, rulesEngine, test)
282
283 rows, err := db.QueryContext(ctx, `SELECT * FROM ea_rules`)
284 assert.NoError(t, err)
285 defer rows.Close()
286
287 for rows.Next() {
288 assert.Fail(t, "Expected no rows")
289 }
290 assert.NoError(t, rows.Err())
291
292 return ctx
293 }).
294 Test("Delete Single Privilege From Rule in Banner", func(ctx f2.Context, t *testing.T) f2.Context {
295 var (
296 db = postgres.FromContextT(ctx, t).DB()
297 )
298 _, err := db.ExecContext(ctx, `
299 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
300 VALUES
301 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3'),
302 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da')
303 ;`,
304 )
305 assert.NoError(t, err)
306
307 test := testCase{
308 url: "/admin/rules/banner/commands/ls/privileges/ea-read?bannerName=myBanner",
309 method: http.MethodDelete,
310 expectedStatus: http.StatusOK,
311 expectedOut: ``,
312 }
313
314 ctx = testEndpoint(ctx, t, rulesEngine, test)
315
316 rows, err := db.QueryContext(ctx, `SELECT banner_edge_id,command_id,privilege_id FROM ea_rules`)
317 assert.NoError(t, err)
318 defer rows.Close()
319
320 var rowCount int
321 for rows.Next() {
322 var bannerID, commandID, privilegeID string
323 rowCount++
324 err = rows.Scan(&bannerID, &commandID, &privilegeID)
325 assert.NoError(t, err)
326
327 assert.Equal(t, "2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a", bannerID)
328 assert.Equal(t, "78587bb1-6ca2-4d2d-a223-1ee642514b97", commandID)
329 assert.Equal(t, "caedabee-ea7a-4421-a608-ec04106e61da", privilegeID)
330 }
331 assert.NoError(t, rows.Err())
332 assert.Equal(t, 1, rowCount)
333
334 _, err = db.ExecContext(ctx, `DELETE from ea_rules;`)
335 assert.NoError(t, err)
336
337 return ctx
338 }).
339 Test("Get Banner Rules for Command", func(ctx f2.Context, t *testing.T) f2.Context {
340 var (
341 db = postgres.FromContextT(ctx, t).DB()
342 )
343 _, err := db.ExecContext(ctx, `
344 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
345 VALUES
346 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3'),
347 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da'),
348 ('8880dd52-f152-44ac-ac76-b37dd3a3a2f2', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da')
349 ;`,
350 )
351 assert.NoError(t, err)
352
353 test := testCase{
354 url: "/admin/rules/banner/commands/ls",
355 method: http.MethodGet,
356 expectedStatus: http.StatusOK,
357 expectedOut: `{
358 "command": {
359 "name": "ls",
360 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97"
361 },
362 "banners": [
363 {
364 "banner": {
365 "name": "myBanner",
366 "id": "2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a"
367 },
368 "privileges": [
369 {
370 "name": "ea-read",
371 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3"
372 },
373 {
374 "name": "ea-write",
375 "id": "caedabee-ea7a-4421-a608-ec04106e61da"
376 }
377 ]
378 },
379 {
380 "banner": {
381 "name": "myBanner2",
382 "id": "8880dd52-f152-44ac-ac76-b37dd3a3a2f2"
383 },
384 "privileges": [
385 {
386 "name": "ea-write",
387 "id": "caedabee-ea7a-4421-a608-ec04106e61da"
388 }
389 ]
390 }
391 ]
392 }`,
393 }
394
395 ctx = testEndpoint(ctx, t, rulesEngine, test)
396
397 _, err = db.ExecContext(ctx, `DELETE from ea_rules;`)
398 assert.NoError(t, err)
399
400 return ctx
401 }).
402 Test("Get No Banner Rules for Command", func(ctx f2.Context, t *testing.T) f2.Context {
403 test := testCase{
404 url: "/admin/rules/banner/commands/ls",
405 method: http.MethodGet,
406 expectedStatus: http.StatusOK,
407 expectedOut: `null`,
408 }
409
410 return testEndpoint(ctx, t, rulesEngine, test)
411 }).
412 Test("Get Banner Rules for Command filtered to single banner", func(ctx f2.Context, t *testing.T) f2.Context {
413 var (
414 db = postgres.FromContextT(ctx, t).DB()
415 )
416 _, err := db.ExecContext(ctx, `
417 INSERT INTO ea_rules (banner_edge_id, command_id, privilege_id)
418 VALUES
419 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'a7c379ea-6e34-4017-8e86-eb545d7856a3'),
420 ('2f9f5965-ed2a-4262-9fd9-9d2d8f8bee8a', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da'),
421 ('8880dd52-f152-44ac-ac76-b37dd3a3a2f2', '78587bb1-6ca2-4d2d-a223-1ee642514b97', 'caedabee-ea7a-4421-a608-ec04106e61da')
422 ;`,
423 )
424 assert.NoError(t, err)
425
426 test := testCase{
427 url: "/admin/rules/banner/commands/ls?bannerName=myBanner",
428 method: http.MethodGet,
429 expectedStatus: http.StatusOK,
430 expectedOut: `{
431 "command": {
432 "name": "ls",
433 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97"
434 },
435 "privileges": [
436 {
437 "name": "ea-read",
438 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3"
439 },
440 {
441 "name": "ea-write",
442 "id": "caedabee-ea7a-4421-a608-ec04106e61da"
443 }
444 ]
445 }`,
446 }
447
448 ctx = testEndpoint(ctx, t, rulesEngine, test)
449
450 _, err = db.ExecContext(ctx, `DELETE from ea_rules;`)
451 assert.NoError(t, err)
452
453 return ctx
454 }).
455 Test("Get No Banner Rules for Command filtered to single banner", func(ctx f2.Context, t *testing.T) f2.Context {
456 test := testCase{
457 url: "/admin/rules/banner/commands/ls?bannerName=myBanner",
458 method: http.MethodGet,
459 expectedStatus: http.StatusOK,
460 expectedOut: `null`,
461 }
462
463 return testEndpoint(ctx, t, rulesEngine, test)
464 }).
465 Feature()
466
467
468 f.Test(t, feat)
469 }
470
471 func TestPostBannerRules(t *testing.T) {
472 var (
473 rulesEngine *gin.Engine
474 )
475
476 feat := f2.NewFeature("Admin POST Banner Rules").
477 Setup("Create Rules Engine server", func(ctx f2.Context, t *testing.T) f2.Context {
478 var db = postgres.FromContextT(ctx, t).DB()
479 rulesEngine, _ = setupRulesEngine(t, db)
480 return ctx
481 }).
482 Setup("Populate Seed Data", func(ctx f2.Context, t *testing.T) f2.Context {
483
484
485 var (
486 db = postgres.FromContextT(ctx, t).DB()
487 )
488
489 _, err := db.ExecContext(ctx, bannerData)
490 require.NoError(t, err)
491
492 return ctx
493 }).
494 Test("POST to invalid Banner", func(ctx f2.Context, t *testing.T) f2.Context {
495 var (
496 db = postgres.FromContextT(ctx, t).DB()
497 )
498
499 test := testCase{
500 url: "/admin/rules/banner/commands?bannerName=anUnknownBanner",
501 method: http.MethodPost,
502 expectedStatus: http.StatusNotFound,
503 body: strings.NewReader(`[
504 {
505 "command": "ls",
506 "privileges": ["ea-read"]
507 },
508 {
509 "command": "cat",
510 "privileges": ["ea-write"]
511 },
512 {
513 "command": "unknownCommand",
514 "privileges": ["unknownPrivilege"]
515 }
516 ]`),
517
518 expectedOut: `{
519 "errors": [
520 {"banner": "anUnknownBanner", "type": "Unknown Banner"},
521 {"banner": "anUnknownBanner", "type": "Unknown Banner"},
522 {"banner": "anUnknownBanner", "type": "Unknown Banner"},
523 {"command": "unknownCommand", "type": "Unknown Command"},
524 {"privilege": "unknownPrivilege", "type": "Unknown Privilege"}
525 ]
526 }`,
527 }
528 ctx = testEndpoint(ctx, t, rulesEngine, test)
529
530 rows, err := db.QueryContext(ctx, `SELECT * FROM ea_rules`)
531 assert.NoError(t, err)
532 defer rows.Close()
533
534 for rows.Next() {
535 assert.Fail(t, "Expected no rows")
536 }
537 assert.NoError(t, rows.Err())
538
539 return ctx
540 }).
541 Test("POST two Rules to Banner", func(ctx f2.Context, t *testing.T) f2.Context {
542 test := testCase{
543 url: "/admin/rules/banner/commands?bannerName=myBanner",
544 method: http.MethodPost,
545 expectedStatus: http.StatusOK,
546 body: strings.NewReader(`[
547 {
548 "command": "ls",
549 "privileges": ["ea-read"]
550 },
551 {
552 "command": "cat",
553 "privileges": ["ea-write"]
554 }
555 ]`),
556 }
557
558 return testEndpoint(ctx, t, rulesEngine, test)
559 }).
560 Test("Confirm Expected State", func(ctx f2.Context, t *testing.T) f2.Context {
561 test := testCase{
562 url: "/admin/rules/banner/commands?bannerName=myBanner",
563 method: http.MethodGet,
564 expectedStatus: http.StatusOK,
565 expectedOut: `[
566 {
567 "command":
568 {
569 "name": "ls",
570 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97"
571 },
572 "privileges": [
573 {
574 "name": "ea-read",
575 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3"
576 }
577 ]
578 },
579 {
580 "command": { "name": "cat", "id": "eb6fc295-a46c-4407-a7a3-1438436d6aee" },
581 "privileges": [
582 { "name": "ea-write", "id": "caedabee-ea7a-4421-a608-ec04106e61da" }
583 ]
584 }
585 ]`,
586 }
587 return testEndpoint(ctx, t, rulesEngine, test)
588 }).
589 Test("POST invalid Rule to Banner", func(ctx f2.Context, t *testing.T) f2.Context {
590 test := testCase{
591 url: "/admin/rules/banner/commands?bannerName=myBanner",
592 method: http.MethodPost,
593 expectedStatus: http.StatusNotFound,
594 body: strings.NewReader(`[
595 {
596 "command": "unknownCommand",
597 "privileges": ["ea-read"]
598 },
599 {
600 "command": "cat",
601 "privileges": ["ea-read"]
602 }
603 ]`),
604 expectedOut: `{
605 "errors": [
606 {
607 "command": "unknownCommand",
608 "type": "Unknown Command"
609 }
610 ]
611 }`,
612 }
613
614 return testEndpoint(ctx, t, rulesEngine, test)
615 }).
616 Test("Confirm Expected State", func(ctx f2.Context, t *testing.T) f2.Context {
617 test := testCase{
618 url: "/admin/rules/banner/commands?bannerName=myBanner",
619 method: http.MethodGet,
620 expectedStatus: http.StatusOK,
621
622 expectedOut: `[
623 {
624 "command":
625 {
626 "name": "ls",
627 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97"
628 },
629 "privileges": [
630 {
631 "name": "ea-read",
632 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3"
633 }
634 ]
635 },
636 {
637 "command": { "name": "cat", "id": "eb6fc295-a46c-4407-a7a3-1438436d6aee" },
638 "privileges": [
639 { "name": "ea-write", "id": "caedabee-ea7a-4421-a608-ec04106e61da" }
640 ]
641 }
642 ]`,
643 }
644 return testEndpoint(ctx, t, rulesEngine, test)
645 }).
646 Test("Post duplicated Rule to Banner", func(ctx f2.Context, t *testing.T) f2.Context {
647
648 test := testCase{
649 url: "/admin/rules/banner/commands?bannerName=myBanner",
650 method: http.MethodPost,
651 expectedStatus: http.StatusOK,
652 body: strings.NewReader(`[
653 {
654 "command": "ls",
655 "privileges": ["ea-read"]
656 },
657 {
658 "command": "cat",
659 "privileges": ["ea-read"]
660 }
661 ]`),
662 }
663
664 return testEndpoint(ctx, t, rulesEngine, test)
665 }).
666 Test("Confirm Expected State", func(ctx f2.Context, t *testing.T) f2.Context {
667
668 test := testCase{
669 url: "/admin/rules/banner/commands?bannerName=myBanner",
670 method: http.MethodGet,
671 expectedStatus: http.StatusOK,
672 expectedOut: `[
673 {
674 "command":
675 {
676 "name": "ls",
677 "id": "78587bb1-6ca2-4d2d-a223-1ee642514b97"
678 },
679 "privileges": [
680 {
681 "name": "ea-read",
682 "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3"
683 }
684 ]
685 },
686 {
687 "command": { "name": "cat", "id": "eb6fc295-a46c-4407-a7a3-1438436d6aee" },
688 "privileges": [
689 { "name": "ea-write", "id": "caedabee-ea7a-4421-a608-ec04106e61da" },
690 { "name": "ea-read", "id": "a7c379ea-6e34-4017-8e86-eb545d7856a3" }
691 ]
692 }
693 ]`,
694 }
695 return testEndpoint(ctx, t, rulesEngine, test)
696 }).
697 Feature()
698
699 f.Test(t, feat)
700 }
701
View as plain text