@lightdash/common 0.1930.2 → 0.1931.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/parseScopes.d.ts +8 -0
- package/dist/cjs/authorization/parseScopes.d.ts.map +1 -0
- package/dist/cjs/authorization/parseScopes.js +27 -0
- package/dist/cjs/authorization/parseScopes.js.map +1 -0
- package/dist/cjs/authorization/parseScopes.test.d.ts +2 -0
- package/dist/cjs/authorization/parseScopes.test.d.ts.map +1 -0
- package/dist/cjs/authorization/parseScopes.test.js +109 -0
- package/dist/cjs/authorization/parseScopes.test.js.map +1 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.d.ts +23 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.d.ts.map +1 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.js +58 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.js.map +1 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.test.d.ts +2 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.test.js +955 -0
- package/dist/cjs/authorization/scopeAbilityBuilder.test.js.map +1 -0
- package/dist/cjs/authorization/scopes.d.ts +8 -0
- package/dist/cjs/authorization/scopes.d.ts.map +1 -0
- package/dist/cjs/authorization/scopes.js +633 -0
- package/dist/cjs/authorization/scopes.js.map +1 -0
- package/dist/cjs/types/scopes.d.ts +30 -3
- package/dist/cjs/types/scopes.d.ts.map +1 -1
- package/dist/cjs/types/scopes.js.map +1 -1
- package/dist/esm/authorization/parseScopes.d.ts +8 -0
- package/dist/esm/authorization/parseScopes.d.ts.map +1 -0
- package/dist/esm/authorization/parseScopes.js +22 -0
- package/dist/esm/authorization/parseScopes.js.map +1 -0
- package/dist/esm/authorization/parseScopes.test.d.ts +2 -0
- package/dist/esm/authorization/parseScopes.test.d.ts.map +1 -0
- package/dist/esm/authorization/parseScopes.test.js +107 -0
- package/dist/esm/authorization/parseScopes.test.js.map +1 -0
- package/dist/esm/authorization/scopeAbilityBuilder.d.ts +23 -0
- package/dist/esm/authorization/scopeAbilityBuilder.d.ts.map +1 -0
- package/dist/esm/authorization/scopeAbilityBuilder.js +54 -0
- package/dist/esm/authorization/scopeAbilityBuilder.js.map +1 -0
- package/dist/esm/authorization/scopeAbilityBuilder.test.d.ts +2 -0
- package/dist/esm/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
- package/dist/esm/authorization/scopeAbilityBuilder.test.js +953 -0
- package/dist/esm/authorization/scopeAbilityBuilder.test.js.map +1 -0
- package/dist/esm/authorization/scopes.d.ts +8 -0
- package/dist/esm/authorization/scopes.d.ts.map +1 -0
- package/dist/esm/authorization/scopes.js +628 -0
- package/dist/esm/authorization/scopes.js.map +1 -0
- package/dist/esm/types/scopes.d.ts +30 -3
- package/dist/esm/types/scopes.d.ts.map +1 -1
- package/dist/esm/types/scopes.js.map +1 -1
- package/dist/tsconfig.types.tsbuildinfo +1 -1
- package/dist/types/authorization/parseScopes.d.ts +8 -0
- package/dist/types/authorization/parseScopes.d.ts.map +1 -0
- package/dist/types/authorization/parseScopes.test.d.ts +2 -0
- package/dist/types/authorization/parseScopes.test.d.ts.map +1 -0
- package/dist/types/authorization/scopeAbilityBuilder.d.ts +23 -0
- package/dist/types/authorization/scopeAbilityBuilder.d.ts.map +1 -0
- package/dist/types/authorization/scopeAbilityBuilder.test.d.ts +2 -0
- package/dist/types/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
- package/dist/types/authorization/scopes.d.ts +8 -0
- package/dist/types/authorization/scopes.d.ts.map +1 -0
- package/dist/types/types/scopes.d.ts +30 -3
- package/dist/types/types/scopes.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/authorization/scopes/index.d.ts +0 -5
- package/dist/cjs/authorization/scopes/index.d.ts.map +0 -1
- package/dist/cjs/authorization/scopes/index.js +0 -372
- package/dist/cjs/authorization/scopes/index.js.map +0 -1
- package/dist/esm/authorization/scopes/index.d.ts +0 -5
- package/dist/esm/authorization/scopes/index.d.ts.map +0 -1
- package/dist/esm/authorization/scopes/index.js +0 -368
- package/dist/esm/authorization/scopes/index.js.map +0 -1
- package/dist/types/authorization/scopes/index.d.ts +0 -5
- package/dist/types/authorization/scopes/index.d.ts.map +0 -1
@@ -1,4 +1,3 @@
|
|
1
|
-
import { type SnakeCase } from 'type-fest';
|
2
1
|
import { type AbilityAction, type CaslSubjectNames } from '../authorization/types';
|
3
2
|
/**
|
4
3
|
* Scope groups to organize permissions in the UI for admins.
|
@@ -12,14 +11,38 @@ export declare enum ScopeGroup {
|
|
12
11
|
AI = "ai",
|
13
12
|
SPOTLIGHT = "spotlight"
|
14
13
|
}
|
14
|
+
/**
|
15
|
+
* Context given to scope getCondition functions
|
16
|
+
*/
|
17
|
+
export type ScopeContext = {
|
18
|
+
organizationUuid: string;
|
19
|
+
projectUuid: string;
|
20
|
+
userUuid?: string;
|
21
|
+
/** The scopes available to the current user */
|
22
|
+
scopes: Set<ScopeName>;
|
23
|
+
isEnterprise: boolean;
|
24
|
+
/** The user's role name in the organization (for dynamic permission logic) */
|
25
|
+
organizationRole: string;
|
26
|
+
/** Configuration for dynamic permissions like PAT */
|
27
|
+
permissionsConfig?: {
|
28
|
+
pat: {
|
29
|
+
enabled: boolean;
|
30
|
+
allowedOrgRoles: string[];
|
31
|
+
};
|
32
|
+
};
|
33
|
+
};
|
34
|
+
/**
|
35
|
+
* The name of the scope, based on ability and subject (e.g. "create:project")
|
36
|
+
*/
|
37
|
+
export type ScopeName = `${AbilityAction}:${CaslSubjectNames}`;
|
15
38
|
/**
|
16
39
|
* A scope defines a specific permission in the system
|
17
40
|
*/
|
18
41
|
export type Scope = {
|
19
42
|
/**
|
20
|
-
* The name of the scope, based on ability and subject (e.g. "create:
|
43
|
+
* The name of the scope, based on ability and subject (e.g. "create:Project")
|
21
44
|
*/
|
22
|
-
name:
|
45
|
+
name: ScopeName;
|
23
46
|
/**
|
24
47
|
* A helpful description of the permission
|
25
48
|
*/
|
@@ -32,5 +55,9 @@ export type Scope = {
|
|
32
55
|
* The grouping from the ScopeGroup enum
|
33
56
|
*/
|
34
57
|
group: ScopeGroup;
|
58
|
+
/**
|
59
|
+
* Get the conditions to be applied to the CASL ability derived from the scope
|
60
|
+
*/
|
61
|
+
getConditions?: (context: ScopeContext) => Record<string, unknown>[];
|
35
62
|
};
|
36
63
|
//# sourceMappingURL=scopes.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../../src/types/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,
|
1
|
+
{"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../../src/types/scopes.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACxB,MAAM,wBAAwB,CAAC;AAEhC;;GAEG;AACH,oBAAY,UAAU;IAClB,OAAO,YAAY;IACnB,kBAAkB,uBAAuB;IACzC,uBAAuB,4BAA4B;IACnD,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,EAAE,OAAO;IACT,SAAS,cAAc;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE;QAChB,GAAG,EAAE;YACD,OAAO,EAAE,OAAO,CAAC;YACjB,eAAe,EAAE,MAAM,EAAE,CAAC;SAC7B,CAAC;KACL,CAAC;CACL,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,GAAG,aAAa,IAAI,gBAAgB,EAAE,CAAC;AAE/D;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG;IAChB;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,KAAK,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;CACxE,CAAC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../src/types/scopes.ts"],"names":[],"mappings":";;;
|
1
|
+
{"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../../src/types/scopes.ts"],"names":[],"mappings":";;;AAKA;;GAEG;AACH,IAAY,UAQX;AARD,WAAY,UAAU;IAClB,iCAAmB,CAAA;IACnB,uDAAyC,CAAA;IACzC,iEAAmD,CAAA;IACnD,2BAAa,CAAA;IACb,iCAAmB,CAAA;IACnB,uBAAS,CAAA;IACT,qCAAuB,CAAA;AAC3B,CAAC,EARW,UAAU,0BAAV,UAAU,QAQrB"}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { type ScopeName } from '../types/scopes';
|
2
|
+
import { type AbilityAction, type CaslSubjectNames } from './types';
|
3
|
+
export declare const parseScope: (scope: string) => [AbilityAction, CaslSubjectNames];
|
4
|
+
export declare const parseScopes: ({ scopes, isEnterprise, }: {
|
5
|
+
scopes: string[];
|
6
|
+
isEnterprise: boolean;
|
7
|
+
}) => Set<ScopeName>;
|
8
|
+
//# sourceMappingURL=parseScopes.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"parseScopes.d.ts","sourceRoot":"","sources":["../../../src/authorization/parseScopes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEpE,eAAO,MAAM,UAAU,UACZ,MAAM,KACd,CAAC,aAAa,EAAE,gBAAgB,CAKlC,CAAC;AAEF,eAAO,MAAM,WAAW,8BAGrB;IACC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;CACzB,KAAG,GAAG,CAAC,SAAS,CAiBhB,CAAC"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { camelCase, upperFirst } from 'lodash';
|
2
|
+
import { ParameterError } from '../types/errors';
|
3
|
+
import { getAllScopeMap } from './scopes';
|
4
|
+
export const parseScope = (scope) => {
|
5
|
+
const [action, subjectPart] = scope.split(':');
|
6
|
+
const subject = upperFirst(camelCase(subjectPart));
|
7
|
+
return [action, subject];
|
8
|
+
};
|
9
|
+
export const parseScopes = ({ scopes, isEnterprise, }) => {
|
10
|
+
const scopeMap = getAllScopeMap({ isEnterprise });
|
11
|
+
const filtered = scopes
|
12
|
+
.map((scope) => parseScope(scope).join(':'))
|
13
|
+
.filter((scope) => {
|
14
|
+
const foundScope = scopeMap[scope];
|
15
|
+
if (!foundScope) {
|
16
|
+
throw new ParameterError(`Invalid scope: ${scope}. Please check the scope name and try again.`);
|
17
|
+
}
|
18
|
+
return true;
|
19
|
+
});
|
20
|
+
return new Set(filtered);
|
21
|
+
};
|
22
|
+
//# sourceMappingURL=parseScopes.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"parseScopes.js","sourceRoot":"","sources":["../../../src/authorization/parseScopes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,CAAC,MAAM,UAAU,GAAG,CACtB,KAAa,EACoB,EAAE;IACnC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;IAEnD,OAAO,CAAC,MAAuB,EAAE,OAA2B,CAAC,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EACxB,MAAM,EACN,YAAY,GAIf,EAAkB,EAAE;IACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM;SAClB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAc,CAAC;SACxD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACd,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEnC,IAAI,CAAC,UAAU,EAAE,CAAC;YACd,MAAM,IAAI,cAAc,CACpB,kBAAkB,KAAK,8CAA8C,CACxE,CAAC;QACN,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEP,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC7B,CAAC,CAAC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"parseScopes.test.d.ts","sourceRoot":"","sources":["../../../src/authorization/parseScopes.test.ts"],"names":[],"mappings":""}
|
@@ -0,0 +1,107 @@
|
|
1
|
+
import { ParameterError } from '../types/errors';
|
2
|
+
import { parseScopes } from './parseScopes';
|
3
|
+
describe('parseScopes', () => {
|
4
|
+
describe('with valid scopes', () => {
|
5
|
+
it('should return a Set of valid scope names for non-enterprise', () => {
|
6
|
+
const result = parseScopes({
|
7
|
+
scopes: ['view:dashboard', 'manage:dashboard'],
|
8
|
+
isEnterprise: false,
|
9
|
+
});
|
10
|
+
expect(result).toBeInstanceOf(Set);
|
11
|
+
expect(result.size).toBe(2);
|
12
|
+
expect(result.has('view:Dashboard')).toBe(true);
|
13
|
+
expect(result.has('manage:Dashboard')).toBe(true);
|
14
|
+
});
|
15
|
+
it('should return a Set of valid scope names for enterprise', () => {
|
16
|
+
const result = parseScopes({
|
17
|
+
scopes: ['view:ai_agent', 'manage:ai_agent'],
|
18
|
+
isEnterprise: true,
|
19
|
+
});
|
20
|
+
expect(result).toBeInstanceOf(Set);
|
21
|
+
expect(result.size).toBe(2);
|
22
|
+
expect(result.has('view:AiAgent')).toBe(true);
|
23
|
+
expect(result.has('manage:AiAgent')).toBe(true);
|
24
|
+
});
|
25
|
+
it('should handle mixed case scope names correctly', () => {
|
26
|
+
const result = parseScopes({
|
27
|
+
scopes: [
|
28
|
+
'export:dashboard_csv',
|
29
|
+
'manage:personal_access_token',
|
30
|
+
],
|
31
|
+
isEnterprise: true,
|
32
|
+
});
|
33
|
+
expect(result.size).toBe(2);
|
34
|
+
expect(result.has('export:DashboardCsv')).toBe(true);
|
35
|
+
expect(result.has('manage:PersonalAccessToken')).toBe(true);
|
36
|
+
});
|
37
|
+
it('should handle single scope correctly', () => {
|
38
|
+
const result = parseScopes({
|
39
|
+
scopes: ['view:project'],
|
40
|
+
isEnterprise: false,
|
41
|
+
});
|
42
|
+
expect(result.size).toBe(1);
|
43
|
+
expect(result.has('view:Project')).toBe(true);
|
44
|
+
});
|
45
|
+
it('should handle empty scopes array', () => {
|
46
|
+
const result = parseScopes({
|
47
|
+
scopes: [],
|
48
|
+
isEnterprise: false,
|
49
|
+
});
|
50
|
+
expect(result).toBeInstanceOf(Set);
|
51
|
+
expect(result.size).toBe(0);
|
52
|
+
});
|
53
|
+
});
|
54
|
+
describe('with invalid scopes', () => {
|
55
|
+
it('should throw ParameterError for invalid scope name', () => {
|
56
|
+
expect(() => parseScopes({
|
57
|
+
scopes: ['view:dashboard', 'invalid:scope'],
|
58
|
+
isEnterprise: false,
|
59
|
+
})).toThrow(ParameterError);
|
60
|
+
expect(() => parseScopes({
|
61
|
+
scopes: ['view:dashboard', 'invalid:scope'],
|
62
|
+
isEnterprise: false,
|
63
|
+
})).toThrow('Invalid scope: invalid:Scope. Please check the scope name and try again.');
|
64
|
+
});
|
65
|
+
it('should throw ParameterError for enterprise scope when not enterprise', () => {
|
66
|
+
expect(() => parseScopes({
|
67
|
+
scopes: ['view:dashboard', 'view:ai_agent'],
|
68
|
+
isEnterprise: false,
|
69
|
+
})).toThrow(ParameterError);
|
70
|
+
expect(() => parseScopes({
|
71
|
+
scopes: ['view:dashboard', 'view:ai_agent'],
|
72
|
+
isEnterprise: false,
|
73
|
+
})).toThrow('Invalid scope: view:AiAgent. Please check the scope name and try again.');
|
74
|
+
});
|
75
|
+
});
|
76
|
+
describe('scope parsing logic', () => {
|
77
|
+
it('should transform snake_case to PascalCase correctly', () => {
|
78
|
+
const result = parseScopes({
|
79
|
+
scopes: [
|
80
|
+
'export:dashboard_csv',
|
81
|
+
'manage:personal_access_token',
|
82
|
+
'view:semantic_viewer',
|
83
|
+
],
|
84
|
+
isEnterprise: true,
|
85
|
+
});
|
86
|
+
expect(result.has('export:DashboardCsv')).toBe(true);
|
87
|
+
expect(result.has('manage:PersonalAccessToken')).toBe(true);
|
88
|
+
expect(result.has('view:SemanticViewer')).toBe(true);
|
89
|
+
});
|
90
|
+
it('should handle camelCase input correctly', () => {
|
91
|
+
const result = parseScopes({
|
92
|
+
scopes: ['view:dashboard', 'manage:savedChart'],
|
93
|
+
isEnterprise: false,
|
94
|
+
});
|
95
|
+
expect(result.has('view:Dashboard')).toBe(true);
|
96
|
+
expect(result.has('manage:SavedChart')).toBe(true);
|
97
|
+
});
|
98
|
+
it('should handle mixed case input correctly', () => {
|
99
|
+
const result = parseScopes({
|
100
|
+
scopes: ['view:underlying_data'],
|
101
|
+
isEnterprise: false,
|
102
|
+
});
|
103
|
+
expect(result.has('view:UnderlyingData')).toBe(true);
|
104
|
+
});
|
105
|
+
});
|
106
|
+
});
|
107
|
+
//# sourceMappingURL=parseScopes.test.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"parseScopes.test.js","sourceRoot":"","sources":["../../../src/authorization/parseScopes.test.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { type MemberAbility } from './types';
|
2
|
+
type BuilderOptions = {
|
3
|
+
organizationUuid: string;
|
4
|
+
projectUuid: string;
|
5
|
+
userUuid?: string;
|
6
|
+
scopes: string[];
|
7
|
+
isEnterprise: boolean;
|
8
|
+
organizationRole: string;
|
9
|
+
permissionsConfig?: {
|
10
|
+
pat: {
|
11
|
+
enabled: boolean;
|
12
|
+
allowedOrgRoles: string[];
|
13
|
+
};
|
14
|
+
};
|
15
|
+
};
|
16
|
+
/**
|
17
|
+
* Build a complete CASL ability from scope names and context
|
18
|
+
* @param context - Context containing organization, project, user, and space access information
|
19
|
+
* @returns CASL Ability with applied permissions
|
20
|
+
*/
|
21
|
+
export declare const buildAbilityFromScopes: (context: BuilderOptions) => MemberAbility;
|
22
|
+
export {};
|
23
|
+
//# sourceMappingURL=scopeAbilityBuilder.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"scopeAbilityBuilder.d.ts","sourceRoot":"","sources":["../../../src/authorization/scopeAbilityBuilder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAC;AAoD7C,KAAK,cAAc,GAAG;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE;QAChB,GAAG,EAAE;YACD,OAAO,EAAE,OAAO,CAAC;YACjB,eAAe,EAAE,MAAM,EAAE,CAAC;SAC7B,CAAC;KACL,CAAC;CACL,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,YACtB,cAAc,KACxB,aAcF,CAAC"}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { Ability, AbilityBuilder } from '@casl/ability';
|
2
|
+
import { parseScope, parseScopes } from './parseScopes';
|
3
|
+
import { getAllScopeMap } from './scopes';
|
4
|
+
const handlePatConfigApplication = (context, builder) => {
|
5
|
+
const { pat } = context?.permissionsConfig || {};
|
6
|
+
const hasPatRule = builder.rules.find((rule) => rule.action === 'manage' && rule.subject === 'PersonalAccessToken');
|
7
|
+
if (!hasPatRule &&
|
8
|
+
pat?.enabled &&
|
9
|
+
pat?.allowedOrgRoles?.includes(context.organizationRole)) {
|
10
|
+
builder.can('manage', 'PersonalAccessToken');
|
11
|
+
}
|
12
|
+
};
|
13
|
+
/**
|
14
|
+
* Apply scope-based abilities to a CASL ability builder
|
15
|
+
* @param scopeNames - Array of scope names to apply
|
16
|
+
* @param context - Context containing organization, project, user, and space access information
|
17
|
+
* @param builder - CASL ability builder to add permissions to
|
18
|
+
*/
|
19
|
+
const applyScopeAbilities = (context, builder) => {
|
20
|
+
const scopeMap = getAllScopeMap({ isEnterprise: context.isEnterprise });
|
21
|
+
context.scopes.forEach((scopeName) => {
|
22
|
+
const scope = scopeMap[scopeName];
|
23
|
+
if (!scope)
|
24
|
+
return;
|
25
|
+
const [action, subject] = parseScope(scopeName);
|
26
|
+
const conditionsList = scope.getConditions
|
27
|
+
? scope.getConditions(context)
|
28
|
+
: [];
|
29
|
+
// Apply each condition set
|
30
|
+
conditionsList.forEach((conditions) => {
|
31
|
+
builder.can(action, subject, conditions);
|
32
|
+
});
|
33
|
+
});
|
34
|
+
handlePatConfigApplication(context, builder);
|
35
|
+
};
|
36
|
+
/**
|
37
|
+
* Build a complete CASL ability from scope names and context
|
38
|
+
* @param context - Context containing organization, project, user, and space access information
|
39
|
+
* @returns CASL Ability with applied permissions
|
40
|
+
*/
|
41
|
+
export const buildAbilityFromScopes = (context) => {
|
42
|
+
const builder = new AbilityBuilder(Ability);
|
43
|
+
const scopes = parseScopes({
|
44
|
+
scopes: context.scopes,
|
45
|
+
isEnterprise: context.isEnterprise,
|
46
|
+
});
|
47
|
+
const parsedContext = {
|
48
|
+
...context,
|
49
|
+
scopes,
|
50
|
+
};
|
51
|
+
applyScopeAbilities(parsedContext, builder);
|
52
|
+
return builder.build();
|
53
|
+
};
|
54
|
+
//# sourceMappingURL=scopeAbilityBuilder.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"scopeAbilityBuilder.js","sourceRoot":"","sources":["../../../src/authorization/scopeAbilityBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,MAAM,0BAA0B,GAAG,CAC/B,OAAqB,EACrB,OAAsC,EACxC,EAAE;IACA,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,iBAAiB,IAAI,EAAE,CAAC;IACjD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CACjC,CAAC,IAAI,EAAE,EAAE,CACL,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,KAAK,qBAAqB,CACzE,CAAC;IAEF,IACI,CAAC,UAAU;QACX,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAC1D,CAAC;QACC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IACjD,CAAC;AACL,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,CACxB,OAAqB,EACrB,OAAsC,EAClC,EAAE;IACN,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAExE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAElC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,cAAc,GAAG,KAAK,CAAC,aAAa;YACtC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC;YAC9B,CAAC,CAAC,EAAE,CAAC;QAET,2BAA2B;QAC3B,cAAc,CAAC,OAAO,CAAC,CAAC,UAAU,EAAE,EAAE;YAClC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,0BAA0B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC,CAAC;AAiBF;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAClC,OAAuB,EACV,EAAE;IACf,MAAM,OAAO,GAAG,IAAI,cAAc,CAAgB,OAAO,CAAC,CAAC;IAE3D,MAAM,MAAM,GAAG,WAAW,CAAC;QACvB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY;KACrC,CAAC,CAAC;IACH,MAAM,aAAa,GAAG;QAClB,GAAG,OAAO;QACV,MAAM;KACT,CAAC;IAEF,mBAAmB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAC5C,OAAO,OAAO,CAAC,KAAK,EAAE,CAAC;AAC3B,CAAC,CAAC"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"scopeAbilityBuilder.test.d.ts","sourceRoot":"","sources":["../../../src/authorization/scopeAbilityBuilder.test.ts"],"names":[],"mappings":""}
|