@mondaydotcomorg/monday-authorization 3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b → 3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-8132586

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/README.md CHANGED
@@ -137,6 +137,18 @@ const canActionInScopeMultipleResponse: ScopedActionResponseObject[] =
137
137
  * /
138
138
  ```
139
139
 
140
+ **Graph API Routing (v3.3.0+):**
141
+
142
+ Starting from version 3.3.0, `canActionInScope` and `canActionInScopeMultiple` can route authorization checks to the Graph API (`authorization-graph` service) instead of the Platform API. This routing is controlled by the Ignite feature flag `navigate-can-action-in-scope-to-graph`.
143
+
144
+ - **Feature Flag**: `navigate-can-action-in-scope-to-graph`
145
+ - **Default Behavior**: When the feature flag is disabled (default), the SDK routes to Platform API (backward compatible)
146
+ - **Graph Routing**: When enabled, authorization checks are routed to the Graph API endpoint `/permissions/is-allowed`
147
+ - **Automatic Fallback**: The SDK automatically falls back to Platform API if the feature flag is disabled
148
+ - **No Code Changes Required**: The routing is transparent - your code doesn't need to change. Simply upgrade to v3.3.0+ and the feature flag controls the routing behavior
149
+
150
+ The Graph API provides the same authorization results with improved performance and scalability. The feature flag allows for gradual rollout and easy rollback if needed.
151
+
140
152
  ### Authorization Attributes API
141
153
 
142
154
  Authorization attributes have 2 options to get called: sync (http request) and async (send to SNS and consumed asynchronously).
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAc1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AA6BD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAsBxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAmF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAuC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
@@ -20,11 +20,11 @@ const mapKeys__default = /*#__PURE__*/_interopDefault(mapKeys);
20
20
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
21
21
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
22
22
  const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
23
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
23
24
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
24
25
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
25
26
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
26
27
  const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
27
- const GRAPH_IS_ALLOWED_PATH = '/permissions/is-allowed';
28
28
  function setRequestFetchOptions(customMondayFetchOptions) {
29
29
  authorizationInternalService.AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
30
30
  }
@@ -99,14 +99,29 @@ class AuthorizationService {
99
99
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
100
100
  const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
101
101
  const internalAuthToken = authorizationInternalService.AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
102
+ const startTime = perf_hooks.performance.now();
103
+ let scopedActionResponseObjects;
102
104
  if (shouldNavigateToGraph) {
103
105
  const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
104
- return this.mapGraphResponse(scopedActions, userId, response);
106
+ scopedActionResponseObjects = this.mapGraphResponse(scopedActions, userId, response);
105
107
  }
106
- const profile = this.getProfile(accountId, userId);
107
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
108
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
109
- return this.mapPlatformResponse(platformResponse);
108
+ else {
109
+ const profile = this.getProfile(accountId, userId);
110
+ const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
111
+ const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
112
+ scopedActionResponseObjects = this.mapPlatformResponse(platformResponse);
113
+ }
114
+ const endTime = perf_hooks.performance.now();
115
+ const time = endTime - startTime;
116
+ const apiType = shouldNavigateToGraph ? 'graph' : 'platform';
117
+ for (const obj of scopedActionResponseObjects) {
118
+ const { action } = obj.scopedAction;
119
+ const resource_type = this.scopeToResource(obj.scopedAction.scope).resourceType;
120
+ const isAuthorized = obj.permit.can;
121
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(resource_type, action, isAuthorized, 200, time, apiType);
122
+ if (obj.permit.can) ;
123
+ }
124
+ return scopedActionResponseObjects;
110
125
  }
111
126
  static buildScopedActionsPayload(scopedActions) {
112
127
  return scopedActions.map(scopedAction => {
@@ -161,7 +176,7 @@ class AuthorizationService {
161
176
  const response = await httpClient.fetch({
162
177
  url: {
163
178
  appName: 'authorization-graph',
164
- path: GRAPH_IS_ALLOWED_PATH,
179
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
165
180
  },
166
181
  method: 'POST',
167
182
  headers: {
@@ -174,11 +189,13 @@ class AuthorizationService {
174
189
  timeout: authorizationInternalService.AuthorizationInternalService.getRequestTimeout(),
175
190
  retryPolicy: authorizationInternalService.AuthorizationInternalService.getRetriesPolicy(),
176
191
  });
192
+ prometheusService.setGraphAvailability(true);
177
193
  return response;
178
194
  }
179
195
  catch (err) {
180
196
  if (err instanceof mondayFetchApi.HttpFetcherError) {
181
197
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
198
+ prometheusService.incrementAuthorizationError(this.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
182
199
  }
183
200
  throw err;
184
201
  }
@@ -223,6 +240,7 @@ class AuthorizationService {
223
240
  catch (err) {
224
241
  if (err instanceof mondayFetchApi.HttpFetcherError) {
225
242
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
243
+ prometheusService.incrementAuthorizationError(this.scopeToResource(this.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
226
244
  }
227
245
  throw err;
228
246
  }
@@ -279,7 +297,7 @@ class AuthorizationService {
279
297
  });
280
298
  }
281
299
  catch (err) {
282
- if (err instanceof httpClient.HttpFetcherError) {
300
+ if (err instanceof mondayFetchApi.HttpFetcherError) {
283
301
  authorizationInternalService.AuthorizationInternalService.throwOnHttpError(err.status, 'isAuthorizedMultiple');
284
302
  }
285
303
  else {
@@ -298,7 +316,7 @@ class AuthorizationService {
298
316
  if (!isAuthorized) {
299
317
  unauthorizedObjects.push(authorizationObject);
300
318
  }
301
- prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
319
+ prometheusService.sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
302
320
  });
303
321
  if (unauthorizedObjects.length > 0) {
304
322
  authorizationInternalService.logger.info({
@@ -1 +1 @@
1
- {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAc1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AA6BD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAsBxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAsC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAmF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
1
+ {"version":3,"file":"authorization-service.d.ts","sourceRoot":"","sources":["../../src/authorization-service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,OAAO,EAAmB,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7F,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,0BAA0B,EAC1B,YAAY,EACb,MAAM,kCAAkC,CAAC;AAe1C,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAC7C;AAED,wBAAgB,sBAAsB,CAAC,wBAAwB,EAAE,kBAAkB,QAElF;AAsCD,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,WAAW,CAAC,MAAC;IACpB,MAAM,CAAC,sCAAsC,CAAC,EAAE,MAAM,CAAC;IACvD,MAAM,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAEnC;;;OAGG;WACU,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,QAAQ,EAAE,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC;WAEhB,YAAY,CACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,2BAA2B,EAAE,mBAAmB,EAAE,GACjD,OAAO,CAAC,iBAAiB,CAAC;IAY7B;;;OAGG;WACU,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAO,GAC1C,OAAO,CAAC,OAAO,CAAC;mBAkBE,6BAA6B;IAclD,OAAO,CAAC,MAAM,CAAC,gBAAgB;WAIlB,gBAAgB,CAC3B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,kBAAkB,CAAC;IAM9B,OAAO,CAAC,MAAM,CAAC,UAAU;WAsBZ,wBAAwB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAyCxC,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAMxC,OAAO,CAAC,MAAM,CAAC,eAAe;IAmB9B,OAAO,CAAC,MAAM,CAAC,qBAAqB;mBAyBf,mBAAmB;IAoCxC,OAAO,CAAC,MAAM,CAAC,gBAAgB;mBAoBV,uBAAuB;IAuC5C,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,mBAAmB;mBAiBb,oBAAoB;mBAUpB,oBAAoB;CAoF1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,KAAA,EACN,sCAAsC,GAAE,MAAiD,QAY1F;AAED,wBAAsB,eAAe,kBAMpC;AAED,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAepG"}
@@ -5,18 +5,18 @@ import mapKeys from 'lodash/mapKeys.js';
5
5
  import { Api } from '@mondaydotcomorg/trident-backend-api';
6
6
  import { HttpFetcherError } from '@mondaydotcomorg/monday-fetch-api';
7
7
  import { getIgniteClient } from '@mondaydotcomorg/ignite-sdk';
8
- import { sendAuthorizationCheckResponseTimeMetric } from './prometheus-service.mjs';
8
+ import { sendAuthorizationCheckResponseTimeMetric, setGraphAvailability, incrementAuthorizationError } from './prometheus-service.mjs';
9
9
  import { AuthorizationInternalService, logger } from './authorization-internal-service.mjs';
10
10
  import { getProfile, PlatformProfile, getAttributionsFromApi } from './attributions-service.mjs';
11
11
 
12
12
  const GRANTED_FEATURE_CACHE_EXPIRATION_SECONDS = 5 * 60;
13
13
  const PLATFORM_AUTHORIZE_PATH = '/internal_ms/authorization/authorize';
14
14
  const PLATFORM_CAN_ACTIONS_IN_SCOPES_PATH = '/internal_ms/authorization/can_actions_in_scopes';
15
+ const CAN_ACTION_IN_SCOPE_GRAPH_PATH = '/permissions/is-allowed';
15
16
  const ALLOWED_SDK_PLATFORM_PROFILES_KEY = 'allowed-sdk-platform-profiles';
16
17
  const IN_RELEASE_SDK_PLATFORM_PROFILES_KEY = 'in-release-sdk-platform-profile';
17
18
  const PLATFORM_PROFILE_RELEASE_FF = 'sdk-platform-profiles';
18
19
  const NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF = 'navigate-can-action-in-scope-to-graph';
19
- const GRAPH_IS_ALLOWED_PATH = '/permissions/is-allowed';
20
20
  function setRequestFetchOptions(customMondayFetchOptions) {
21
21
  AuthorizationInternalService.setRequestFetchOptions(customMondayFetchOptions);
22
22
  }
@@ -91,14 +91,29 @@ class AuthorizationService {
91
91
  static async canActionInScopeMultiple(accountId, userId, scopedActions) {
92
92
  const shouldNavigateToGraph = Boolean(this.igniteClient?.isReleased(NAVIGATE_CAN_ACTION_IN_SCOPE_TO_GRAPH_FF, { accountId, userId }));
93
93
  const internalAuthToken = AuthorizationInternalService.generateInternalAuthToken(accountId, userId);
94
+ const startTime = performance.now();
95
+ let scopedActionResponseObjects;
94
96
  if (shouldNavigateToGraph) {
95
97
  const response = await this.fetchGraphIsAllowed(internalAuthToken, scopedActions);
96
- return this.mapGraphResponse(scopedActions, userId, response);
98
+ scopedActionResponseObjects = this.mapGraphResponse(scopedActions, userId, response);
97
99
  }
98
- const profile = this.getProfile(accountId, userId);
99
- const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
100
- const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
101
- return this.mapPlatformResponse(platformResponse);
100
+ else {
101
+ const profile = this.getProfile(accountId, userId);
102
+ const scopedActionsPayload = this.buildScopedActionsPayload(scopedActions);
103
+ const platformResponse = await this.fetchPlatformCanActions(profile, internalAuthToken, userId, scopedActionsPayload);
104
+ scopedActionResponseObjects = this.mapPlatformResponse(platformResponse);
105
+ }
106
+ const endTime = performance.now();
107
+ const time = endTime - startTime;
108
+ const apiType = shouldNavigateToGraph ? 'graph' : 'platform';
109
+ for (const obj of scopedActionResponseObjects) {
110
+ const { action } = obj.scopedAction;
111
+ const resource_type = this.scopeToResource(obj.scopedAction.scope).resourceType;
112
+ const isAuthorized = obj.permit.can;
113
+ sendAuthorizationCheckResponseTimeMetric(resource_type, action, isAuthorized, 200, time, apiType);
114
+ if (obj.permit.can) ;
115
+ }
116
+ return scopedActionResponseObjects;
102
117
  }
103
118
  static buildScopedActionsPayload(scopedActions) {
104
119
  return scopedActions.map(scopedAction => {
@@ -153,7 +168,7 @@ class AuthorizationService {
153
168
  const response = await httpClient.fetch({
154
169
  url: {
155
170
  appName: 'authorization-graph',
156
- path: GRAPH_IS_ALLOWED_PATH,
171
+ path: CAN_ACTION_IN_SCOPE_GRAPH_PATH,
157
172
  },
158
173
  method: 'POST',
159
174
  headers: {
@@ -166,11 +181,13 @@ class AuthorizationService {
166
181
  timeout: AuthorizationInternalService.getRequestTimeout(),
167
182
  retryPolicy: AuthorizationInternalService.getRetriesPolicy(),
168
183
  });
184
+ setGraphAvailability(true);
169
185
  return response;
170
186
  }
171
187
  catch (err) {
172
188
  if (err instanceof HttpFetcherError) {
173
189
  AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
190
+ incrementAuthorizationError(this.scopeToResource(scopedActions[0].scope).resourceType, scopedActions[0].action, err.status);
174
191
  }
175
192
  throw err;
176
193
  }
@@ -215,6 +232,7 @@ class AuthorizationService {
215
232
  catch (err) {
216
233
  if (err instanceof HttpFetcherError) {
217
234
  AuthorizationInternalService.throwOnHttpError(err.status, 'canActionInScopeMultiple');
235
+ incrementAuthorizationError(this.scopeToResource(this.toCamelCase(scopedActionsPayload[0].scope)).resourceType, scopedActionsPayload[0].action, err.status);
218
236
  }
219
237
  throw err;
220
238
  }
@@ -271,7 +289,7 @@ class AuthorizationService {
271
289
  });
272
290
  }
273
291
  catch (err) {
274
- if (err instanceof httpClient.HttpFetcherError) {
292
+ if (err instanceof HttpFetcherError) {
275
293
  AuthorizationInternalService.throwOnHttpError(err.status, 'isAuthorizedMultiple');
276
294
  }
277
295
  else {
@@ -290,7 +308,7 @@ class AuthorizationService {
290
308
  if (!isAuthorized) {
291
309
  unauthorizedObjects.push(authorizationObject);
292
310
  }
293
- sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time);
311
+ sendAuthorizationCheckResponseTimeMetric(authorizationObject.resource_type, authorizationObject.action, isAuthorized, 200, time, 'platform');
294
312
  });
295
313
  if (unauthorizedObjects.length > 0) {
296
314
  logger.info({
@@ -6,5 +6,8 @@ export declare const METRICS: {
6
6
  };
7
7
  export declare function setPrometheus(customPrometheus: any): void;
8
8
  export declare function getMetricsManager(): any;
9
- export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number): void;
9
+ export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number, apiType?: 'platform' | 'graph'): void;
10
+ export declare function incrementAuthorizationSuccess(resourceType: string, action: Action): void;
11
+ export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number): void;
12
+ export declare function setGraphAvailability(isAvailable: boolean): void;
10
13
  //# sourceMappingURL=prometheus-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAU7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,QASb"}
1
+ {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAiB7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,UAAU,GAAG,OAAoB,QAW3C;AAED,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAI;AAEtF,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAI;AAExG,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,QAAI"}
@@ -7,26 +7,38 @@ const METRICS = {
7
7
  };
8
8
  const authorizationCheckResponseTimeMetricConfig = {
9
9
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
10
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
10
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
11
11
  description: 'Authorization check response time summary',
12
12
  };
13
13
  function setPrometheus(customPrometheus) {
14
14
  prometheus = customPrometheus;
15
+ if (!prometheus) {
16
+ authorizationCheckResponseTimeMetric = null;
17
+ return;
18
+ }
15
19
  const { METRICS_TYPES } = prometheus;
16
- authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
20
+ const metricsManager = getMetricsManager();
21
+ if (metricsManager) {
22
+ authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
23
+ }
17
24
  }
18
25
  function getMetricsManager() {
19
26
  return prometheus?.metricsManager;
20
27
  }
21
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
28
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
22
29
  try {
23
30
  if (authorizationCheckResponseTimeMetric) {
24
- authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
31
+ authorizationCheckResponseTimeMetric
32
+ .labels(resourceType, action, isAuthorized, responseStatus, apiType)
33
+ .observe(time);
25
34
  }
26
35
  }
27
36
  catch (e) {
28
37
  // ignore
29
38
  }
30
39
  }
40
+ function incrementAuthorizationSuccess(resourceType, action) { }
41
+ function incrementAuthorizationError(resourceType, action, statusCode) { }
42
+ function setGraphAvailability(isAvailable) { }
31
43
 
32
- export { METRICS, getMetricsManager, sendAuthorizationCheckResponseTimeMetric, setPrometheus };
44
+ export { METRICS, getMetricsManager, incrementAuthorizationError, incrementAuthorizationSuccess, sendAuthorizationCheckResponseTimeMetric, setGraphAvailability, setPrometheus };
@@ -6,5 +6,8 @@ export declare const METRICS: {
6
6
  };
7
7
  export declare function setPrometheus(customPrometheus: any): void;
8
8
  export declare function getMetricsManager(): any;
9
- export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number): void;
9
+ export declare function sendAuthorizationCheckResponseTimeMetric(resourceType: string, action: Action, isAuthorized: boolean, responseStatus: number, time: number, apiType?: 'platform' | 'graph'): void;
10
+ export declare function incrementAuthorizationSuccess(resourceType: string, action: Action): void;
11
+ export declare function incrementAuthorizationError(resourceType: string, action: Action, statusCode: number): void;
12
+ export declare function setGraphAvailability(isAvailable: boolean): void;
10
13
  //# sourceMappingURL=prometheus-service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAU7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,QASb"}
1
+ {"version":3,"file":"prometheus-service.d.ts","sourceRoot":"","sources":["../src/prometheus-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAKzC,eAAO,MAAM,OAAO;;;;CAInB,CAAC;AAQF,wBAAgB,aAAa,CAAC,gBAAgB,KAAA,QAiB7C;AAED,wBAAgB,iBAAiB,QAEhC;AAED,wBAAgB,wCAAwC,CACtD,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,UAAU,GAAG,OAAoB,QAW3C;AAED,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAI;AAEtF,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAI;AAExG,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,OAAO,QAAI"}
@@ -9,29 +9,44 @@ const METRICS = {
9
9
  };
10
10
  const authorizationCheckResponseTimeMetricConfig = {
11
11
  name: METRICS.AUTHORIZATION_CHECK_RESPONSE_TIME,
12
- labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus'],
12
+ labels: ['resourceType', 'action', 'isAuthorized', 'responseStatus', 'apiType'],
13
13
  description: 'Authorization check response time summary',
14
14
  };
15
15
  function setPrometheus(customPrometheus) {
16
16
  prometheus = customPrometheus;
17
+ if (!prometheus) {
18
+ authorizationCheckResponseTimeMetric = null;
19
+ return;
20
+ }
17
21
  const { METRICS_TYPES } = prometheus;
18
- authorizationCheckResponseTimeMetric = getMetricsManager().addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
22
+ const metricsManager = getMetricsManager();
23
+ if (metricsManager) {
24
+ authorizationCheckResponseTimeMetric = metricsManager.addMetric(METRICS_TYPES.SUMMARY, authorizationCheckResponseTimeMetricConfig.name, authorizationCheckResponseTimeMetricConfig.labels, authorizationCheckResponseTimeMetricConfig.description);
25
+ }
19
26
  }
20
27
  function getMetricsManager() {
21
28
  return prometheus?.metricsManager;
22
29
  }
23
- function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time) {
30
+ function sendAuthorizationCheckResponseTimeMetric(resourceType, action, isAuthorized, responseStatus, time, apiType = 'platform') {
24
31
  try {
25
32
  if (authorizationCheckResponseTimeMetric) {
26
- authorizationCheckResponseTimeMetric.labels(resourceType, action, isAuthorized, responseStatus).observe(time);
33
+ authorizationCheckResponseTimeMetric
34
+ .labels(resourceType, action, isAuthorized, responseStatus, apiType)
35
+ .observe(time);
27
36
  }
28
37
  }
29
38
  catch (e) {
30
39
  // ignore
31
40
  }
32
41
  }
42
+ function incrementAuthorizationSuccess(resourceType, action) { }
43
+ function incrementAuthorizationError(resourceType, action, statusCode) { }
44
+ function setGraphAvailability(isAvailable) { }
33
45
 
34
46
  exports.METRICS = METRICS;
35
47
  exports.getMetricsManager = getMetricsManager;
48
+ exports.incrementAuthorizationError = incrementAuthorizationError;
49
+ exports.incrementAuthorizationSuccess = incrementAuthorizationSuccess;
36
50
  exports.sendAuthorizationCheckResponseTimeMetric = sendAuthorizationCheckResponseTimeMetric;
51
+ exports.setGraphAvailability = setGraphAvailability;
37
52
  exports.setPrometheus = setPrometheus;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/monday-authorization",
3
- "version": "3.2.3-feature-bashanye-navigate-can-action-in-scope-to-graph-af77c6b",
3
+ "version": "3.3.0-feature-bashanye-navigate-can-action-in-scope-to-graph-8132586",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "BSD-3-Clause",
@@ -62,4 +62,4 @@
62
62
  "url": "https://github.com/DaPulse/authorization-domain.git",
63
63
  "directory": "packages/monday-authorization"
64
64
  }
65
- }
65
+ }
package/CHANGELOG.md DELETED
@@ -1,46 +0,0 @@
1
- # Change Log
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
- and this project adheres to [Semantic Versioning](http://semver.org/).
7
-
8
- ## [2.0.0] - 2025-04-07
9
-
10
- ### ⚠ MAJOR CHANGE - PLEASE READ
11
-
12
- ### Fixed
13
-
14
- - Calls to the monolith will be spread across the different profiles - `api-internal`, `slow` and `internal` (originally, all the calls to the platform went directly to `monday-app`)
15
-
16
- ## [1.2.9] - 2024-10-06
17
-
18
- ### Added
19
-
20
- - [`authz/bashanye/add-async-resource-attributes-support`](https://github.com/DaPulse/monday-npm-packages/pull/6859)
21
- - `AuthorizationAttributesService` - now supports async upsert and delete - requests sent through SNS-SQS).
22
-
23
- ## [1.2.3] - 2024-06-10
24
-
25
- ### Added
26
-
27
- - [`feature/yarden/resource-attributes-api-support-authz-sdk (#5826)`](https://github.com/DaPulse/monday-npm-packages/pull/5826)
28
- - `AuthorizationAttributesService` - now supports upsert (`upsertResourceAttributesSync`) and delete (`deleteResourceAttributesSync`) resource attributes in the authorization MS
29
-
30
- ## [1.2.0] - 2024-01-05
31
-
32
- ### Added
33
-
34
- - `isAuthorized` now return the unauthorized objects - regardless to the unauthorized ids (which may be missing resource ids if resource has no id, like `feature` e.g.)
35
-
36
- ## [1.1.0] - 2023-08-09
37
-
38
- ### ⚠ BREAKING CHANGES
39
-
40
- - `canActionInScope` now returns an object of type `{ can: boolean; reason: string; }` instead of `boolean`.
41
- This version is considered minor because no one uses this function yet.
42
-
43
- ### Changed
44
-
45
- - [`feature/idan/can-action-in-scope/change-behavior-on-error (#3689)`](https://github.com/DaPulse/monday-npm-packages/pull/3689)
46
- - `canActionInScope`, `canActionInScopeMultiple` and `isAuthorized` are now throwing an error instead of returning `false` when an error occurs as part of the authorization http request (status code is not 2XX)