@lightdash/common 0.1947.0 → 0.1948.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/authorization/projectMemberAbility.d.ts.map +1 -1
- package/dist/cjs/authorization/projectMemberAbility.js +0 -4
- package/dist/cjs/authorization/projectMemberAbility.js.map +1 -1
- package/dist/cjs/authorization/roleToScopeMapping.d.ts.map +1 -1
- package/dist/cjs/authorization/roleToScopeMapping.js +11 -10
- package/dist/cjs/authorization/roleToScopeMapping.js.map +1 -1
- package/dist/cjs/authorization/roleToScopeParity.test.d.ts +2 -0
- package/dist/cjs/authorization/roleToScopeParity.test.d.ts.map +1 -0
- package/dist/cjs/authorization/roleToScopeParity.test.js +195 -0
- package/dist/cjs/authorization/roleToScopeParity.test.js.map +1 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.d.ts.map +1 -1
- package/dist/cjs/authorization/scopeAbilityBuilder.js +10 -7
- package/dist/cjs/authorization/scopeAbilityBuilder.js.map +1 -1
- package/dist/cjs/authorization/scopeAbilityBuilder.test.js +312 -89
- package/dist/cjs/authorization/scopeAbilityBuilder.test.js.map +1 -1
- package/dist/cjs/authorization/scopes.d.ts.map +1 -1
- package/dist/cjs/authorization/scopes.js +102 -90
- package/dist/cjs/authorization/scopes.js.map +1 -1
- package/dist/cjs/types/scopes.d.ts +2 -2
- package/dist/cjs/types/scopes.d.ts.map +1 -1
- package/dist/esm/authorization/projectMemberAbility.d.ts.map +1 -1
- package/dist/esm/authorization/projectMemberAbility.js +0 -4
- package/dist/esm/authorization/projectMemberAbility.js.map +1 -1
- package/dist/esm/authorization/roleToScopeMapping.d.ts.map +1 -1
- package/dist/esm/authorization/roleToScopeMapping.js +11 -10
- package/dist/esm/authorization/roleToScopeMapping.js.map +1 -1
- package/dist/esm/authorization/roleToScopeParity.test.d.ts +2 -0
- package/dist/esm/authorization/roleToScopeParity.test.d.ts.map +1 -0
- package/dist/esm/authorization/roleToScopeParity.test.js +193 -0
- package/dist/esm/authorization/roleToScopeParity.test.js.map +1 -0
- package/dist/esm/authorization/scopeAbilityBuilder.d.ts.map +1 -1
- package/dist/esm/authorization/scopeAbilityBuilder.js +10 -7
- package/dist/esm/authorization/scopeAbilityBuilder.js.map +1 -1
- package/dist/esm/authorization/scopeAbilityBuilder.test.js +312 -89
- package/dist/esm/authorization/scopeAbilityBuilder.test.js.map +1 -1
- package/dist/esm/authorization/scopes.d.ts.map +1 -1
- package/dist/esm/authorization/scopes.js +102 -90
- package/dist/esm/authorization/scopes.js.map +1 -1
- package/dist/esm/types/scopes.d.ts +2 -2
- package/dist/esm/types/scopes.d.ts.map +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/authorization/projectMemberAbility.d.ts.map +1 -1
- package/dist/types/authorization/roleToScopeMapping.d.ts.map +1 -1
- package/dist/types/authorization/roleToScopeParity.test.d.ts +2 -0
- package/dist/types/authorization/roleToScopeParity.test.d.ts.map +1 -0
- package/dist/types/authorization/scopeAbilityBuilder.d.ts.map +1 -1
- package/dist/types/authorization/scopes.d.ts.map +1 -1
- package/dist/types/types/scopes.d.ts +2 -2
- package/dist/types/types/scopes.d.ts.map +1 -1
- package/package.json +1 -1
@@ -22,7 +22,7 @@ describe('scopeAbilityBuilder', () => {
|
|
22
22
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
23
23
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
24
24
|
...baseContextWithOrg,
|
25
|
-
scopes: ['view:
|
25
|
+
scopes: ['view:Organization'],
|
26
26
|
}, builder);
|
27
27
|
const ability = builder.build();
|
28
28
|
expect(ability.can('view', (0, ability_1.subject)('Organization', {
|
@@ -38,7 +38,7 @@ describe('scopeAbilityBuilder', () => {
|
|
38
38
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
39
39
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
40
40
|
...baseContext,
|
41
|
-
scopes: ['view:
|
41
|
+
scopes: ['view:Dashboard'],
|
42
42
|
}, builder);
|
43
43
|
const ability = builder.build();
|
44
44
|
// Should be able to view public dashboards
|
@@ -62,7 +62,7 @@ describe('scopeAbilityBuilder', () => {
|
|
62
62
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
63
63
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
64
64
|
...contextWithUser,
|
65
|
-
scopes: ['view:
|
65
|
+
scopes: ['view:Dashboard'],
|
66
66
|
}, builder);
|
67
67
|
const ability = builder.build();
|
68
68
|
// Can view dashboards with user access
|
@@ -80,7 +80,7 @@ describe('scopeAbilityBuilder', () => {
|
|
80
80
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
81
81
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
82
82
|
...projectContext,
|
83
|
-
scopes: ['view:
|
83
|
+
scopes: ['view:Project'],
|
84
84
|
}, builder);
|
85
85
|
const ability = builder.build();
|
86
86
|
expect(ability.can('view', (0, ability_1.subject)('Project', {
|
@@ -92,7 +92,7 @@ describe('scopeAbilityBuilder', () => {
|
|
92
92
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
93
93
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
94
94
|
...baseContextWithOrg,
|
95
|
-
scopes: ['create:
|
95
|
+
scopes: ['create:Project'],
|
96
96
|
}, builder);
|
97
97
|
const ability = builder.build();
|
98
98
|
// Can create preview projects
|
@@ -114,7 +114,7 @@ describe('scopeAbilityBuilder', () => {
|
|
114
114
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
115
115
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
116
116
|
...editorContext,
|
117
|
-
scopes: ['manage:
|
117
|
+
scopes: ['manage:Dashboard'],
|
118
118
|
}, builder);
|
119
119
|
const ability = builder.build();
|
120
120
|
// Can manage dashboards where user is editor
|
@@ -136,7 +136,7 @@ describe('scopeAbilityBuilder', () => {
|
|
136
136
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
137
137
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
138
138
|
...adminContext,
|
139
|
-
scopes: ['manage:
|
139
|
+
scopes: ['manage:Space'],
|
140
140
|
}, builder);
|
141
141
|
const ability = builder.build();
|
142
142
|
// Can manage spaces where user is admin
|
@@ -158,7 +158,7 @@ describe('scopeAbilityBuilder', () => {
|
|
158
158
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
159
159
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
160
160
|
...userContext,
|
161
|
-
scopes: ['view:
|
161
|
+
scopes: ['view:JobStatus@self'],
|
162
162
|
}, builder);
|
163
163
|
const ability = builder.build();
|
164
164
|
// Can view job status created by the user
|
@@ -179,17 +179,17 @@ describe('scopeAbilityBuilder', () => {
|
|
179
179
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
180
180
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
181
181
|
...userContext,
|
182
|
-
scopes: ['manage:
|
182
|
+
scopes: ['manage:AiAgentThread@self'],
|
183
183
|
}, builder);
|
184
184
|
const ability = builder.build();
|
185
185
|
// Can manage user's own AI agent threads
|
186
186
|
expect(ability.can('manage', (0, ability_1.subject)('AiAgentThread', {
|
187
|
-
|
187
|
+
projectUuid: 'project-123',
|
188
188
|
userUuid: 'user-456',
|
189
189
|
}))).toBe(true);
|
190
190
|
// Cannot manage another user's threads
|
191
191
|
expect(ability.can('manage', (0, ability_1.subject)('AiAgentThread', {
|
192
|
-
|
192
|
+
projectUuid: 'project-123',
|
193
193
|
userUuid: 'other-user',
|
194
194
|
}))).toBe(false);
|
195
195
|
});
|
@@ -198,7 +198,7 @@ describe('scopeAbilityBuilder', () => {
|
|
198
198
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
199
199
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
200
200
|
...baseContext,
|
201
|
-
scopes: ['view:
|
201
|
+
scopes: ['view:Analytics', 'manage:Tags'],
|
202
202
|
}, builder);
|
203
203
|
const ability = builder.build();
|
204
204
|
expect(ability.can('view', (0, ability_1.subject)('Analytics', {
|
@@ -234,11 +234,7 @@ describe('scopeAbilityBuilder', () => {
|
|
234
234
|
organizationUuid: 'org-123',
|
235
235
|
isEnterprise: false,
|
236
236
|
organizationRole: 'admin',
|
237
|
-
scopes: [
|
238
|
-
'view:dashboard',
|
239
|
-
'manage:saved_chart',
|
240
|
-
'view:project',
|
241
|
-
],
|
237
|
+
scopes: ['view:Dashboard', 'manage:SavedChart', 'view:Project'],
|
242
238
|
};
|
243
239
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
244
240
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)(context, builder);
|
@@ -269,7 +265,7 @@ describe('scopeAbilityBuilder', () => {
|
|
269
265
|
const contextWithOrgManage = {
|
270
266
|
...baseContext,
|
271
267
|
userUuid: 'user-456',
|
272
|
-
scopes: ['manage:
|
268
|
+
scopes: ['manage:Organization', 'manage:SavedChart'],
|
273
269
|
};
|
274
270
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
275
271
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)(contextWithOrgManage, builder);
|
@@ -290,7 +286,7 @@ describe('scopeAbilityBuilder', () => {
|
|
290
286
|
const contextWithoutOrgManage = {
|
291
287
|
...baseContext,
|
292
288
|
userUuid: 'user-456',
|
293
|
-
scopes: ['manage:
|
289
|
+
scopes: ['manage:SavedChart@space'],
|
294
290
|
};
|
295
291
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
296
292
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)(contextWithoutOrgManage, builder);
|
@@ -317,7 +313,7 @@ describe('scopeAbilityBuilder', () => {
|
|
317
313
|
const contextWithProjectManage = {
|
318
314
|
...baseContext,
|
319
315
|
userUuid: 'user-456',
|
320
|
-
scopes: ['manage:
|
316
|
+
scopes: ['manage:Project', 'manage:Space'],
|
321
317
|
};
|
322
318
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
323
319
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)(contextWithProjectManage, builder);
|
@@ -344,12 +340,12 @@ describe('scopeAbilityBuilder', () => {
|
|
344
340
|
const contextWithOrgManage = {
|
345
341
|
...baseContext,
|
346
342
|
userUuid: 'user-456',
|
347
|
-
scopes: ['manage:
|
343
|
+
scopes: ['manage:Organization', 'promote:Dashboard'],
|
348
344
|
};
|
349
345
|
const contextWithoutOrgManage = {
|
350
346
|
...baseContext,
|
351
347
|
userUuid: 'user-456',
|
352
|
-
scopes: ['promote:
|
348
|
+
scopes: ['promote:Dashboard@space'],
|
353
349
|
};
|
354
350
|
// Test dashboard promotion with organization management
|
355
351
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
@@ -381,6 +377,82 @@ describe('scopeAbilityBuilder', () => {
|
|
381
377
|
}))).toBe(false);
|
382
378
|
});
|
383
379
|
});
|
380
|
+
describe('AI agent thread permissions with modifiers', () => {
|
381
|
+
it('should handle view:ai_agent_thread@self permissions', () => {
|
382
|
+
const contextWithUser = {
|
383
|
+
...baseContext,
|
384
|
+
userUuid: 'user-456',
|
385
|
+
isEnterprise: true,
|
386
|
+
};
|
387
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
388
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
389
|
+
...contextWithUser,
|
390
|
+
scopes: ['view:AiAgentThread@self'],
|
391
|
+
}, builder);
|
392
|
+
const ability = builder.build();
|
393
|
+
// Can view own AI agent threads
|
394
|
+
expect(ability.can('view', (0, ability_1.subject)('AiAgentThread', {
|
395
|
+
projectUuid: 'project-123',
|
396
|
+
userUuid: 'user-456',
|
397
|
+
}))).toBe(true);
|
398
|
+
// Cannot view other users' threads
|
399
|
+
expect(ability.can('view', (0, ability_1.subject)('AiAgentThread', {
|
400
|
+
projectUuid: 'project-123',
|
401
|
+
userUuid: 'other-user',
|
402
|
+
}))).toBe(false);
|
403
|
+
});
|
404
|
+
it('should handle manage:ai_agent_thread@self permissions', () => {
|
405
|
+
const contextWithUser = {
|
406
|
+
...baseContext,
|
407
|
+
userUuid: 'user-456',
|
408
|
+
isEnterprise: true,
|
409
|
+
};
|
410
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
411
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
412
|
+
...contextWithUser,
|
413
|
+
userUuid: 'user-456',
|
414
|
+
scopes: ['manage:AiAgentThread@self'],
|
415
|
+
}, builder);
|
416
|
+
const ability = builder.build();
|
417
|
+
// Can manage own AI agent threads
|
418
|
+
expect(ability.can('manage', (0, ability_1.subject)('AiAgentThread', {
|
419
|
+
projectUuid: 'project-123',
|
420
|
+
userUuid: 'user-456',
|
421
|
+
}))).toBe(true);
|
422
|
+
// Cannot manage other users' threads
|
423
|
+
expect(ability.can('manage', (0, ability_1.subject)('AiAgentThread', {
|
424
|
+
userUuid: 'other-user',
|
425
|
+
}))).toBe(false);
|
426
|
+
});
|
427
|
+
it('should handle view:ai_agent_thread permissions for all threads', () => {
|
428
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
429
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
430
|
+
...baseContextWithOrg,
|
431
|
+
isEnterprise: true,
|
432
|
+
scopes: ['view:AiAgentThread'],
|
433
|
+
}, builder);
|
434
|
+
const ability = builder.build();
|
435
|
+
// Can view any AI agent thread
|
436
|
+
expect(ability.can('view', (0, ability_1.subject)('AiAgentThread', {
|
437
|
+
organizationUuid: 'org-123',
|
438
|
+
userUuid: 'any-user',
|
439
|
+
}))).toBe(true);
|
440
|
+
});
|
441
|
+
it('should handle manage:ai_agent_thread permissions for all threads', () => {
|
442
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
443
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
444
|
+
...baseContextWithOrg,
|
445
|
+
isEnterprise: true,
|
446
|
+
scopes: ['manage:AiAgentThread'],
|
447
|
+
}, builder);
|
448
|
+
const ability = builder.build();
|
449
|
+
// Can manage any AI agent thread
|
450
|
+
expect(ability.can('manage', (0, ability_1.subject)('AiAgentThread', {
|
451
|
+
organizationUuid: 'org-123',
|
452
|
+
userUuid: 'any-user',
|
453
|
+
}))).toBe(true);
|
454
|
+
});
|
455
|
+
});
|
384
456
|
describe('edge cases and error handling', () => {
|
385
457
|
it('should handle empty scope array', () => {
|
386
458
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
@@ -395,7 +467,7 @@ describe('scopeAbilityBuilder', () => {
|
|
395
467
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
396
468
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
397
469
|
...contextWithoutUser,
|
398
|
-
scopes: ['view:
|
470
|
+
scopes: ['view:Dashboard'],
|
399
471
|
}, builder);
|
400
472
|
const ability = builder.build();
|
401
473
|
// Should only allow viewing public dashboards
|
@@ -415,8 +487,8 @@ describe('scopeAbilityBuilder', () => {
|
|
415
487
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
416
488
|
...baseContext,
|
417
489
|
scopes: [
|
418
|
-
'view:
|
419
|
-
'view:
|
490
|
+
'view:Dashboard',
|
491
|
+
'view:Project',
|
420
492
|
'invalid:scope',
|
421
493
|
],
|
422
494
|
}, builder);
|
@@ -433,9 +505,9 @@ describe('scopeAbilityBuilder', () => {
|
|
433
505
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
434
506
|
...baseContext,
|
435
507
|
scopes: [
|
436
|
-
'view:
|
437
|
-
'manage:
|
438
|
-
'view:
|
508
|
+
'view:Dashboard',
|
509
|
+
'manage:SavedChart',
|
510
|
+
'view:Space',
|
439
511
|
],
|
440
512
|
}, builder);
|
441
513
|
const ability = builder.build();
|
@@ -458,7 +530,7 @@ describe('scopeAbilityBuilder', () => {
|
|
458
530
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
459
531
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
460
532
|
...baseContext,
|
461
|
-
scopes: ['view:
|
533
|
+
scopes: ['view:SavedChart'],
|
462
534
|
}, builder);
|
463
535
|
const ability = builder.build();
|
464
536
|
// Should not access saved chart from different project
|
@@ -478,7 +550,7 @@ describe('scopeAbilityBuilder', () => {
|
|
478
550
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
479
551
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
480
552
|
...contextWithUser,
|
481
|
-
scopes: ['view:
|
553
|
+
scopes: ['view:Dashboard'],
|
482
554
|
}, builder);
|
483
555
|
const ability = builder.build();
|
484
556
|
// Can view private dashboard with viewer access
|
@@ -518,7 +590,7 @@ describe('scopeAbilityBuilder', () => {
|
|
518
590
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
519
591
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
520
592
|
...contextWithUser,
|
521
|
-
scopes: ['manage:
|
593
|
+
scopes: ['manage:Dashboard@space'],
|
522
594
|
}, builder);
|
523
595
|
const ability = builder.build();
|
524
596
|
// Can manage dashboard with editor role
|
@@ -565,7 +637,7 @@ describe('scopeAbilityBuilder', () => {
|
|
565
637
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
566
638
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
567
639
|
...contextWithUser,
|
568
|
-
scopes: ['manage:
|
640
|
+
scopes: ['manage:Space@assigned'],
|
569
641
|
}, builder);
|
570
642
|
const ability = builder.build();
|
571
643
|
// Can manage space with admin role
|
@@ -603,7 +675,7 @@ describe('scopeAbilityBuilder', () => {
|
|
603
675
|
});
|
604
676
|
});
|
605
677
|
describe('job and job status permissions', () => {
|
606
|
-
it('should handle view:job permissions', () => {
|
678
|
+
it('should handle view:job@self permissions', () => {
|
607
679
|
const contextWithUser = {
|
608
680
|
...baseContext,
|
609
681
|
userUuid: 'user-456',
|
@@ -611,7 +683,7 @@ describe('scopeAbilityBuilder', () => {
|
|
611
683
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
612
684
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
613
685
|
...contextWithUser,
|
614
|
-
scopes: ['view:
|
686
|
+
scopes: ['view:Job@self'],
|
615
687
|
}, builder);
|
616
688
|
const ability = builder.build();
|
617
689
|
// Can view own jobs
|
@@ -623,30 +695,31 @@ describe('scopeAbilityBuilder', () => {
|
|
623
695
|
userUuid: 'other-user',
|
624
696
|
}))).toBe(false);
|
625
697
|
});
|
626
|
-
it('should handle view:job_status permissions for
|
698
|
+
it('should handle view:job_status@self permissions for user context', () => {
|
627
699
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
628
700
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
629
701
|
...baseContext,
|
630
|
-
|
702
|
+
userUuid: 'user-456',
|
703
|
+
scopes: ['view:JobStatus@self'],
|
631
704
|
}, builder);
|
632
705
|
const ability = builder.build();
|
633
|
-
//
|
706
|
+
// Can view own job status
|
634
707
|
expect(ability.can('view', (0, ability_1.subject)('JobStatus', {
|
635
|
-
|
636
|
-
}))).toBe(
|
637
|
-
// Cannot view job status
|
708
|
+
createdByUserUuid: 'user-456',
|
709
|
+
}))).toBe(true);
|
710
|
+
// Cannot view other users' job status
|
638
711
|
expect(ability.can('view', (0, ability_1.subject)('JobStatus', {
|
639
|
-
|
712
|
+
createdByUserUuid: 'other-user',
|
640
713
|
}))).toBe(false);
|
641
714
|
});
|
642
|
-
it('should handle view:job_status permissions
|
715
|
+
it('should handle view:job_status permissions for all job status', () => {
|
643
716
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
644
717
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
645
718
|
...baseContextWithOrg,
|
646
|
-
scopes: ['view:
|
719
|
+
scopes: ['view:JobStatus'],
|
647
720
|
}, builder);
|
648
721
|
const ability = builder.build();
|
649
|
-
// Can view all job status in organization
|
722
|
+
// Can view all job status in organization
|
650
723
|
expect(ability.can('view', (0, ability_1.subject)('JobStatus', {
|
651
724
|
organizationUuid: 'org-123',
|
652
725
|
}))).toBe(true);
|
@@ -655,7 +728,70 @@ describe('scopeAbilityBuilder', () => {
|
|
655
728
|
organizationUuid: 'different-org',
|
656
729
|
}))).toBe(false);
|
657
730
|
});
|
658
|
-
it('should handle view:
|
731
|
+
it('should handle view:job permissions for all jobs', () => {
|
732
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
733
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
734
|
+
...baseContext,
|
735
|
+
scopes: ['view:Job'],
|
736
|
+
}, builder);
|
737
|
+
const ability = builder.build();
|
738
|
+
// Can view any job
|
739
|
+
expect(ability.can('view', (0, ability_1.subject)('Job', {
|
740
|
+
organizationUuid: 'org-123',
|
741
|
+
projectUuid: 'project-123',
|
742
|
+
userUuid: 'any-user',
|
743
|
+
}))).toBe(true);
|
744
|
+
});
|
745
|
+
});
|
746
|
+
describe('space-based permissions modifiers', () => {
|
747
|
+
it('should handle manage:dashboard@space permissions', () => {
|
748
|
+
const contextWithUser = {
|
749
|
+
...baseContextWithOrg,
|
750
|
+
userUuid: 'user-456',
|
751
|
+
};
|
752
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
753
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
754
|
+
...contextWithUser,
|
755
|
+
scopes: ['manage:Dashboard@space'],
|
756
|
+
}, builder);
|
757
|
+
const ability = builder.build();
|
758
|
+
// Can manage dashboard with editor role
|
759
|
+
expect(ability.can('manage', (0, ability_1.subject)('Dashboard', {
|
760
|
+
organizationUuid: 'org-123',
|
761
|
+
access: [
|
762
|
+
{
|
763
|
+
userUuid: 'user-456',
|
764
|
+
role: space_1.SpaceMemberRole.EDITOR,
|
765
|
+
},
|
766
|
+
],
|
767
|
+
}))).toBe(true);
|
768
|
+
// Can manage dashboard with admin role
|
769
|
+
expect(ability.can('manage', (0, ability_1.subject)('Dashboard', {
|
770
|
+
organizationUuid: 'org-123',
|
771
|
+
access: [
|
772
|
+
{
|
773
|
+
userUuid: 'user-456',
|
774
|
+
role: space_1.SpaceMemberRole.ADMIN,
|
775
|
+
},
|
776
|
+
],
|
777
|
+
}))).toBe(true);
|
778
|
+
// Cannot manage dashboard with viewer role
|
779
|
+
expect(ability.can('manage', (0, ability_1.subject)('Dashboard', {
|
780
|
+
organizationUuid: 'org-123',
|
781
|
+
access: [
|
782
|
+
{
|
783
|
+
userUuid: 'user-456',
|
784
|
+
role: space_1.SpaceMemberRole.VIEWER,
|
785
|
+
},
|
786
|
+
],
|
787
|
+
}))).toBe(false);
|
788
|
+
// Cannot manage dashboard without access
|
789
|
+
expect(ability.can('manage', (0, ability_1.subject)('Dashboard', {
|
790
|
+
organizationUuid: 'org-123',
|
791
|
+
access: [],
|
792
|
+
}))).toBe(false);
|
793
|
+
});
|
794
|
+
it('should handle manage:saved_chart@space permissions', () => {
|
659
795
|
const contextWithUser = {
|
660
796
|
...baseContext,
|
661
797
|
userUuid: 'user-456',
|
@@ -663,16 +799,102 @@ describe('scopeAbilityBuilder', () => {
|
|
663
799
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
664
800
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
665
801
|
...contextWithUser,
|
666
|
-
scopes: ['
|
802
|
+
scopes: ['manage:SavedChart@space'],
|
667
803
|
}, builder);
|
668
804
|
const ability = builder.build();
|
669
|
-
// Can
|
670
|
-
expect(ability.can('
|
671
|
-
|
805
|
+
// Can manage saved chart with editor role
|
806
|
+
expect(ability.can('manage', (0, ability_1.subject)('SavedChart', {
|
807
|
+
projectUuid: 'project-123',
|
808
|
+
access: [
|
809
|
+
{
|
810
|
+
userUuid: 'user-456',
|
811
|
+
role: space_1.SpaceMemberRole.EDITOR,
|
812
|
+
},
|
813
|
+
],
|
672
814
|
}))).toBe(true);
|
673
|
-
//
|
674
|
-
expect(ability.can('
|
675
|
-
|
815
|
+
// Can manage saved chart with admin role
|
816
|
+
expect(ability.can('manage', (0, ability_1.subject)('SavedChart', {
|
817
|
+
projectUuid: 'project-123',
|
818
|
+
access: [
|
819
|
+
{
|
820
|
+
userUuid: 'user-456',
|
821
|
+
role: space_1.SpaceMemberRole.ADMIN,
|
822
|
+
},
|
823
|
+
],
|
824
|
+
}))).toBe(true);
|
825
|
+
// Cannot manage without proper access
|
826
|
+
expect(ability.can('manage', (0, ability_1.subject)('SavedChart', {
|
827
|
+
projectUuid: 'project-123',
|
828
|
+
access: [
|
829
|
+
{
|
830
|
+
userUuid: 'other-user',
|
831
|
+
role: space_1.SpaceMemberRole.EDITOR,
|
832
|
+
},
|
833
|
+
],
|
834
|
+
}))).toBe(false);
|
835
|
+
});
|
836
|
+
it('should handle promote:dashboard@space permissions', () => {
|
837
|
+
const contextWithUser = {
|
838
|
+
...baseContext,
|
839
|
+
userUuid: 'user-456',
|
840
|
+
};
|
841
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
842
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
843
|
+
...contextWithUser,
|
844
|
+
scopes: ['promote:Dashboard@space'],
|
845
|
+
}, builder);
|
846
|
+
const ability = builder.build();
|
847
|
+
// Can promote dashboard with editor access
|
848
|
+
expect(ability.can('promote', (0, ability_1.subject)('Dashboard', {
|
849
|
+
projectUuid: 'project-123',
|
850
|
+
access: [
|
851
|
+
{
|
852
|
+
userUuid: 'user-456',
|
853
|
+
role: space_1.SpaceMemberRole.EDITOR,
|
854
|
+
},
|
855
|
+
],
|
856
|
+
}))).toBe(true);
|
857
|
+
// Cannot promote without editor access
|
858
|
+
expect(ability.can('promote', (0, ability_1.subject)('Dashboard', {
|
859
|
+
projectUuid: 'project-123',
|
860
|
+
access: [
|
861
|
+
{
|
862
|
+
userUuid: 'user-456',
|
863
|
+
role: space_1.SpaceMemberRole.VIEWER,
|
864
|
+
},
|
865
|
+
],
|
866
|
+
}))).toBe(false);
|
867
|
+
});
|
868
|
+
it('should handle manage:semantic_viewer@space permissions', () => {
|
869
|
+
const contextWithUser = {
|
870
|
+
...baseContextWithOrg,
|
871
|
+
userUuid: 'user-456',
|
872
|
+
};
|
873
|
+
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
874
|
+
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
875
|
+
...contextWithUser,
|
876
|
+
scopes: ['manage:SemanticViewer@space'],
|
877
|
+
}, builder);
|
878
|
+
const ability = builder.build();
|
879
|
+
// Can manage semantic viewer with editor role
|
880
|
+
expect(ability.can('manage', (0, ability_1.subject)('SemanticViewer', {
|
881
|
+
organizationUuid: 'org-123',
|
882
|
+
access: [
|
883
|
+
{
|
884
|
+
userUuid: 'user-456',
|
885
|
+
role: space_1.SpaceMemberRole.EDITOR,
|
886
|
+
},
|
887
|
+
],
|
888
|
+
}))).toBe(true);
|
889
|
+
// Cannot manage without editor role
|
890
|
+
expect(ability.can('manage', (0, ability_1.subject)('SemanticViewer', {
|
891
|
+
organizationUuid: 'org-123',
|
892
|
+
access: [
|
893
|
+
{
|
894
|
+
userUuid: 'user-456',
|
895
|
+
role: space_1.SpaceMemberRole.VIEWER,
|
896
|
+
},
|
897
|
+
],
|
676
898
|
}))).toBe(false);
|
677
899
|
});
|
678
900
|
});
|
@@ -681,7 +903,7 @@ describe('scopeAbilityBuilder', () => {
|
|
681
903
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
682
904
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
683
905
|
...baseContext,
|
684
|
-
scopes: ['view:
|
906
|
+
scopes: ['view:SemanticViewer'],
|
685
907
|
}, builder);
|
686
908
|
const ability = builder.build();
|
687
909
|
expect(ability.can('view', (0, ability_1.subject)('SemanticViewer', {
|
@@ -693,14 +915,14 @@ describe('scopeAbilityBuilder', () => {
|
|
693
915
|
const contextWithOrgManage = {
|
694
916
|
...baseContextWithOrg,
|
695
917
|
userUuid: 'user-456',
|
696
|
-
scopes: ['manage:
|
918
|
+
scopes: ['manage:Organization'],
|
697
919
|
};
|
698
920
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
699
921
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
700
922
|
...contextWithOrgManage,
|
701
923
|
scopes: [
|
702
|
-
'manage:
|
703
|
-
'manage:
|
924
|
+
'manage:Organization',
|
925
|
+
'manage:SemanticViewer',
|
704
926
|
],
|
705
927
|
}, builder);
|
706
928
|
const ability = builder.build();
|
@@ -717,7 +939,7 @@ describe('scopeAbilityBuilder', () => {
|
|
717
939
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
718
940
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
719
941
|
...contextWithUser,
|
720
|
-
scopes: ['manage:
|
942
|
+
scopes: ['manage:SemanticViewer@space'],
|
721
943
|
}, builder);
|
722
944
|
const ability = builder.build();
|
723
945
|
// Can manage semantic viewer with editor role
|
@@ -747,7 +969,7 @@ describe('scopeAbilityBuilder', () => {
|
|
747
969
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
748
970
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
749
971
|
...baseContext,
|
750
|
-
scopes: ['create:
|
972
|
+
scopes: ['create:Space'],
|
751
973
|
}, builder);
|
752
974
|
const ability = builder.build();
|
753
975
|
expect(ability.can('create', (0, ability_1.subject)('Space', {
|
@@ -761,7 +983,7 @@ describe('scopeAbilityBuilder', () => {
|
|
761
983
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
762
984
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
763
985
|
...baseContext,
|
764
|
-
scopes: ['manage:
|
986
|
+
scopes: ['manage:ExportCsv'],
|
765
987
|
}, builder);
|
766
988
|
const ability = builder.build();
|
767
989
|
expect(ability.can('manage', (0, ability_1.subject)('ExportCsv', {
|
@@ -773,7 +995,7 @@ describe('scopeAbilityBuilder', () => {
|
|
773
995
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
774
996
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
775
997
|
...baseContext,
|
776
|
-
scopes: ['manage:
|
998
|
+
scopes: ['manage:ChangeCsvResults'],
|
777
999
|
}, builder);
|
778
1000
|
const ability = builder.build();
|
779
1001
|
expect(ability.can('manage', (0, ability_1.subject)('ChangeCsvResults', {
|
@@ -787,7 +1009,7 @@ describe('scopeAbilityBuilder', () => {
|
|
787
1009
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
788
1010
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
789
1011
|
...baseContext,
|
790
|
-
scopes: ['view:
|
1012
|
+
scopes: ['view:UnderlyingData'],
|
791
1013
|
}, builder);
|
792
1014
|
const ability = builder.build();
|
793
1015
|
expect(ability.can('view', (0, ability_1.subject)('UnderlyingData', {
|
@@ -801,7 +1023,7 @@ describe('scopeAbilityBuilder', () => {
|
|
801
1023
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
802
1024
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
803
1025
|
...baseContext,
|
804
|
-
scopes: ['manage:
|
1026
|
+
scopes: ['manage:SqlRunner'],
|
805
1027
|
}, builder);
|
806
1028
|
const ability = builder.build();
|
807
1029
|
expect(ability.can('manage', (0, ability_1.subject)('SqlRunner', {
|
@@ -813,7 +1035,7 @@ describe('scopeAbilityBuilder', () => {
|
|
813
1035
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
814
1036
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
815
1037
|
...baseContext,
|
816
|
-
scopes: ['manage:
|
1038
|
+
scopes: ['manage:CustomSql'],
|
817
1039
|
}, builder);
|
818
1040
|
const ability = builder.build();
|
819
1041
|
expect(ability.can('manage', (0, ability_1.subject)('CustomSql', {
|
@@ -828,7 +1050,7 @@ describe('scopeAbilityBuilder', () => {
|
|
828
1050
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
829
1051
|
...baseContext,
|
830
1052
|
userUuid: 'user-456',
|
831
|
-
scopes: ['delete:
|
1053
|
+
scopes: ['delete:Project@self'],
|
832
1054
|
}, builder);
|
833
1055
|
const ability = builder.build();
|
834
1056
|
// Can delete specific project
|
@@ -841,21 +1063,22 @@ describe('scopeAbilityBuilder', () => {
|
|
841
1063
|
type: projects_1.ProjectType.PREVIEW,
|
842
1064
|
}))).toBe(false);
|
843
1065
|
});
|
844
|
-
it('should handle delete:project for preview projects', () => {
|
1066
|
+
it('should handle delete:project@self for own preview projects', () => {
|
845
1067
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
846
1068
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
847
|
-
...
|
848
|
-
|
1069
|
+
...baseContext,
|
1070
|
+
userUuid: 'user-456',
|
1071
|
+
scopes: ['delete:Project@self'],
|
849
1072
|
}, builder);
|
850
1073
|
const ability = builder.build();
|
851
|
-
// Can delete preview projects in
|
1074
|
+
// Can delete preview projects in a project
|
852
1075
|
expect(ability.can('delete', (0, ability_1.subject)('Project', {
|
853
|
-
|
1076
|
+
createdByUserUuid: 'user-456',
|
854
1077
|
type: projects_1.ProjectType.PREVIEW,
|
855
1078
|
}))).toBe(true);
|
856
1079
|
// Cannot delete default projects
|
857
1080
|
expect(ability.can('delete', (0, ability_1.subject)('Project', {
|
858
|
-
|
1081
|
+
createdByUserUuid: 'user-456',
|
859
1082
|
type: projects_1.ProjectType.DEFAULT,
|
860
1083
|
}))).toBe(false);
|
861
1084
|
});
|
@@ -865,7 +1088,7 @@ describe('scopeAbilityBuilder', () => {
|
|
865
1088
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
866
1089
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
867
1090
|
...baseContext,
|
868
|
-
scopes: ['view:
|
1091
|
+
scopes: ['view:PinnedItems'],
|
869
1092
|
}, builder);
|
870
1093
|
const ability = builder.build();
|
871
1094
|
expect(ability.can('view', (0, ability_1.subject)('PinnedItems', {
|
@@ -877,7 +1100,7 @@ describe('scopeAbilityBuilder', () => {
|
|
877
1100
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
878
1101
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
879
1102
|
...baseContext,
|
880
|
-
scopes: ['manage:
|
1103
|
+
scopes: ['manage:PinnedItems'],
|
881
1104
|
}, builder);
|
882
1105
|
const ability = builder.build();
|
883
1106
|
expect(ability.can('manage', (0, ability_1.subject)('PinnedItems', {
|
@@ -891,7 +1114,7 @@ describe('scopeAbilityBuilder', () => {
|
|
891
1114
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
892
1115
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
893
1116
|
...baseContext,
|
894
|
-
scopes: ['manage:
|
1117
|
+
scopes: ['manage:Explore'],
|
895
1118
|
}, builder);
|
896
1119
|
const ability = builder.build();
|
897
1120
|
expect(ability.can('manage', (0, ability_1.subject)('Explore', {
|
@@ -905,7 +1128,7 @@ describe('scopeAbilityBuilder', () => {
|
|
905
1128
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
906
1129
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
907
1130
|
...baseContext,
|
908
|
-
scopes: ['create:
|
1131
|
+
scopes: ['create:VirtualView'],
|
909
1132
|
}, builder);
|
910
1133
|
const ability = builder.build();
|
911
1134
|
expect(ability.can('create', (0, ability_1.subject)('VirtualView', {
|
@@ -922,7 +1145,7 @@ describe('scopeAbilityBuilder', () => {
|
|
922
1145
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
923
1146
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
924
1147
|
...baseContext,
|
925
|
-
scopes: ['delete:
|
1148
|
+
scopes: ['delete:VirtualView'],
|
926
1149
|
}, builder);
|
927
1150
|
const ability = builder.build();
|
928
1151
|
expect(ability.can('delete', (0, ability_1.subject)('VirtualView', {
|
@@ -939,7 +1162,7 @@ describe('scopeAbilityBuilder', () => {
|
|
939
1162
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
940
1163
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
941
1164
|
...baseContext,
|
942
|
-
scopes: ['manage:
|
1165
|
+
scopes: ['manage:VirtualView'],
|
943
1166
|
}, builder);
|
944
1167
|
const ability = builder.build();
|
945
1168
|
// Should be able to manage (create and delete)
|
@@ -962,9 +1185,9 @@ describe('scopeAbilityBuilder', () => {
|
|
962
1185
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
963
1186
|
...baseContextWithOrg,
|
964
1187
|
scopes: [
|
965
|
-
'create:
|
966
|
-
'delete:
|
967
|
-
'manage:
|
1188
|
+
'create:VirtualView',
|
1189
|
+
'delete:VirtualView',
|
1190
|
+
'manage:VirtualView',
|
968
1191
|
],
|
969
1192
|
}, builder);
|
970
1193
|
const ability = builder.build();
|
@@ -987,9 +1210,9 @@ describe('scopeAbilityBuilder', () => {
|
|
987
1210
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
988
1211
|
...baseContextWithOrg,
|
989
1212
|
scopes: [
|
990
|
-
'create:
|
991
|
-
'delete:
|
992
|
-
'manage:
|
1213
|
+
'create:VirtualView',
|
1214
|
+
'delete:VirtualView',
|
1215
|
+
'manage:VirtualView',
|
993
1216
|
],
|
994
1217
|
}, builder);
|
995
1218
|
const ability = builder.build();
|
@@ -1014,7 +1237,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1014
1237
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
1015
1238
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
1016
1239
|
...baseContextWithOrg,
|
1017
|
-
scopes: ['view:
|
1240
|
+
scopes: ['view:OrganizationMemberProfile'],
|
1018
1241
|
}, builder);
|
1019
1242
|
const ability = builder.build();
|
1020
1243
|
expect(ability.can('view', (0, ability_1.subject)('OrganizationMemberProfile', {
|
@@ -1031,7 +1254,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1031
1254
|
const builder = new ability_1.AbilityBuilder(ability_1.Ability);
|
1032
1255
|
(0, scopeAbilityBuilder_1.buildAbilityFromScopes)({
|
1033
1256
|
...baseContext,
|
1034
|
-
scopes: ['manage:
|
1257
|
+
scopes: ['manage:OrganizationMemberProfile'],
|
1035
1258
|
}, builder);
|
1036
1259
|
const ability = builder.build();
|
1037
1260
|
expect(ability.can('manage', (0, ability_1.subject)('OrganizationMemberProfile', {
|
@@ -1047,7 +1270,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1047
1270
|
...baseContext,
|
1048
1271
|
isEnterprise: true,
|
1049
1272
|
organizationRole: 'admin',
|
1050
|
-
scopes: ['manage:
|
1273
|
+
scopes: ['manage:PersonalAccessToken'],
|
1051
1274
|
permissionsConfig: {
|
1052
1275
|
pat: {
|
1053
1276
|
enabled: true,
|
@@ -1064,7 +1287,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1064
1287
|
...baseContext,
|
1065
1288
|
isEnterprise: true,
|
1066
1289
|
organizationRole: 'admin',
|
1067
|
-
scopes: ['manage:
|
1290
|
+
scopes: ['manage:PersonalAccessToken'],
|
1068
1291
|
permissionsConfig: {
|
1069
1292
|
pat: {
|
1070
1293
|
enabled: false,
|
@@ -1081,7 +1304,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1081
1304
|
...baseContext,
|
1082
1305
|
isEnterprise: true,
|
1083
1306
|
organizationRole: 'developer',
|
1084
|
-
scopes: ['manage:
|
1307
|
+
scopes: ['manage:PersonalAccessToken'],
|
1085
1308
|
permissionsConfig: {
|
1086
1309
|
pat: {
|
1087
1310
|
enabled: true,
|
@@ -1098,7 +1321,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1098
1321
|
...baseContext,
|
1099
1322
|
isEnterprise: true,
|
1100
1323
|
organizationRole: 'admin',
|
1101
|
-
scopes: ['manage:
|
1324
|
+
scopes: ['manage:PersonalAccessToken'],
|
1102
1325
|
// No permissionsConfig provided
|
1103
1326
|
}, builder);
|
1104
1327
|
const ability = builder.build();
|
@@ -1110,7 +1333,7 @@ describe('scopeAbilityBuilder', () => {
|
|
1110
1333
|
...baseContext,
|
1111
1334
|
isEnterprise: true,
|
1112
1335
|
organizationRole: '', // Empty organization role
|
1113
|
-
scopes: ['manage:
|
1336
|
+
scopes: ['manage:PersonalAccessToken'],
|
1114
1337
|
permissionsConfig: {
|
1115
1338
|
pat: {
|
1116
1339
|
enabled: true,
|