@lightdash/common 0.1930.3 → 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.
Files changed (70) hide show
  1. package/dist/cjs/authorization/parseScopes.d.ts +8 -0
  2. package/dist/cjs/authorization/parseScopes.d.ts.map +1 -0
  3. package/dist/cjs/authorization/parseScopes.js +27 -0
  4. package/dist/cjs/authorization/parseScopes.js.map +1 -0
  5. package/dist/cjs/authorization/parseScopes.test.d.ts +2 -0
  6. package/dist/cjs/authorization/parseScopes.test.d.ts.map +1 -0
  7. package/dist/cjs/authorization/parseScopes.test.js +109 -0
  8. package/dist/cjs/authorization/parseScopes.test.js.map +1 -0
  9. package/dist/cjs/authorization/scopeAbilityBuilder.d.ts +23 -0
  10. package/dist/cjs/authorization/scopeAbilityBuilder.d.ts.map +1 -0
  11. package/dist/cjs/authorization/scopeAbilityBuilder.js +58 -0
  12. package/dist/cjs/authorization/scopeAbilityBuilder.js.map +1 -0
  13. package/dist/cjs/authorization/scopeAbilityBuilder.test.d.ts +2 -0
  14. package/dist/cjs/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
  15. package/dist/cjs/authorization/scopeAbilityBuilder.test.js +955 -0
  16. package/dist/cjs/authorization/scopeAbilityBuilder.test.js.map +1 -0
  17. package/dist/cjs/authorization/scopes.d.ts +8 -0
  18. package/dist/cjs/authorization/scopes.d.ts.map +1 -0
  19. package/dist/cjs/authorization/scopes.js +633 -0
  20. package/dist/cjs/authorization/scopes.js.map +1 -0
  21. package/dist/cjs/types/scopes.d.ts +30 -3
  22. package/dist/cjs/types/scopes.d.ts.map +1 -1
  23. package/dist/cjs/types/scopes.js.map +1 -1
  24. package/dist/esm/authorization/parseScopes.d.ts +8 -0
  25. package/dist/esm/authorization/parseScopes.d.ts.map +1 -0
  26. package/dist/esm/authorization/parseScopes.js +22 -0
  27. package/dist/esm/authorization/parseScopes.js.map +1 -0
  28. package/dist/esm/authorization/parseScopes.test.d.ts +2 -0
  29. package/dist/esm/authorization/parseScopes.test.d.ts.map +1 -0
  30. package/dist/esm/authorization/parseScopes.test.js +107 -0
  31. package/dist/esm/authorization/parseScopes.test.js.map +1 -0
  32. package/dist/esm/authorization/scopeAbilityBuilder.d.ts +23 -0
  33. package/dist/esm/authorization/scopeAbilityBuilder.d.ts.map +1 -0
  34. package/dist/esm/authorization/scopeAbilityBuilder.js +54 -0
  35. package/dist/esm/authorization/scopeAbilityBuilder.js.map +1 -0
  36. package/dist/esm/authorization/scopeAbilityBuilder.test.d.ts +2 -0
  37. package/dist/esm/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
  38. package/dist/esm/authorization/scopeAbilityBuilder.test.js +953 -0
  39. package/dist/esm/authorization/scopeAbilityBuilder.test.js.map +1 -0
  40. package/dist/esm/authorization/scopes.d.ts +8 -0
  41. package/dist/esm/authorization/scopes.d.ts.map +1 -0
  42. package/dist/esm/authorization/scopes.js +628 -0
  43. package/dist/esm/authorization/scopes.js.map +1 -0
  44. package/dist/esm/types/scopes.d.ts +30 -3
  45. package/dist/esm/types/scopes.d.ts.map +1 -1
  46. package/dist/esm/types/scopes.js.map +1 -1
  47. package/dist/tsconfig.types.tsbuildinfo +1 -1
  48. package/dist/types/authorization/parseScopes.d.ts +8 -0
  49. package/dist/types/authorization/parseScopes.d.ts.map +1 -0
  50. package/dist/types/authorization/parseScopes.test.d.ts +2 -0
  51. package/dist/types/authorization/parseScopes.test.d.ts.map +1 -0
  52. package/dist/types/authorization/scopeAbilityBuilder.d.ts +23 -0
  53. package/dist/types/authorization/scopeAbilityBuilder.d.ts.map +1 -0
  54. package/dist/types/authorization/scopeAbilityBuilder.test.d.ts +2 -0
  55. package/dist/types/authorization/scopeAbilityBuilder.test.d.ts.map +1 -0
  56. package/dist/types/authorization/scopes.d.ts +8 -0
  57. package/dist/types/authorization/scopes.d.ts.map +1 -0
  58. package/dist/types/types/scopes.d.ts +30 -3
  59. package/dist/types/types/scopes.d.ts.map +1 -1
  60. package/package.json +1 -1
  61. package/dist/cjs/authorization/scopes/index.d.ts +0 -5
  62. package/dist/cjs/authorization/scopes/index.d.ts.map +0 -1
  63. package/dist/cjs/authorization/scopes/index.js +0 -372
  64. package/dist/cjs/authorization/scopes/index.js.map +0 -1
  65. package/dist/esm/authorization/scopes/index.d.ts +0 -5
  66. package/dist/esm/authorization/scopes/index.d.ts.map +0 -1
  67. package/dist/esm/authorization/scopes/index.js +0 -368
  68. package/dist/esm/authorization/scopes/index.js.map +0 -1
  69. package/dist/types/authorization/scopes/index.d.ts +0 -5
  70. 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:project")
43
+ * The name of the scope, based on ability and subject (e.g. "create:Project")
21
44
  */
22
- name: Lowercase<`${AbilityAction}:${SnakeCase<CaslSubjectNames>}`>;
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,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,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,KAAK,GAAG;IAChB;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC,GAAG,aAAa,IAAI,SAAS,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACnE;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,KAAK,EAAE,UAAU,CAAC;CACrB,CAAC"}
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":";;;AAMA;;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"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=parseScopes.test.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=scopeAbilityBuilder.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopeAbilityBuilder.test.d.ts","sourceRoot":"","sources":["../../../src/authorization/scopeAbilityBuilder.test.ts"],"names":[],"mappings":""}