Browse Source

fix(integrations): Show warning if the privileges for the integration are going to be elevated (#58593)

If the privileges for the integration are going to be elevated (as here)
<img width="1150" alt="image"
src="https://github.com/getsentry/sentry/assets/1127549/b494b5bd-72d0-4273-bb33-fbebae3ae073">
then we should show a callout:
<img width="1170" alt="image"
src="https://github.com/getsentry/sentry/assets/1127549/58fd09f6-88ff-4d29-b39d-7ad48f8f9799">

---------

Co-authored-by: Seiji Chew <67301797+schew2381@users.noreply.github.com>
Alexander Tarasov 1 year ago
parent
commit
386b6e449f

+ 8 - 4
static/app/utils/consolidatedScopes.tsx

@@ -5,9 +5,10 @@ import pick from 'lodash/pick';
 import {Permissions} from 'sentry/types';
 
 const PERMISSION_LEVELS = {
-  read: 0,
-  write: 1,
-  admin: 2,
+  'no-access': 0,
+  read: 1,
+  write: 2,
+  admin: 3,
 };
 
 const HUMAN_RESOURCE_NAMES = {
@@ -47,6 +48,9 @@ const permissionLevel = (scope: string): number => {
 
 const compareScopes = (a: string, b: string) => permissionLevel(a) - permissionLevel(b);
 
+const comparePermissionLevels = (a: string, b: string) =>
+  PERMISSION_LEVELS[a] - PERMISSION_LEVELS[b];
+
 /**
  * Return the most permissive scope for each resource.
  *
@@ -132,4 +136,4 @@ function toPermissions(scopes: string[]): PermissionLevelResources {
   return {...defaultPermissions, ...permissions};
 }
 
-export {toPermissions, toResourcePermissions};
+export {comparePermissionLevels, toPermissions, toResourcePermissions};

+ 42 - 1
static/app/views/settings/organizationDeveloperSettings/permissionsObserver.tsx

@@ -1,11 +1,15 @@
 import {Component, Fragment} from 'react';
 
+import {Alert} from 'sentry/components/alert';
 import Panel from 'sentry/components/panels/panel';
 import PanelBody from 'sentry/components/panels/panelBody';
 import PanelHeader from 'sentry/components/panels/panelHeader';
 import {t} from 'sentry/locale';
 import {Permissions, Scope, WebhookEvent} from 'sentry/types';
-import {toResourcePermissions} from 'sentry/utils/consolidatedScopes';
+import {
+  comparePermissionLevels,
+  toResourcePermissions,
+} from 'sentry/utils/consolidatedScopes';
 import PermissionSelection from 'sentry/views/settings/organizationDeveloperSettings/permissionSelection';
 import Subscriptions from 'sentry/views/settings/organizationDeveloperSettings/resourceSubscriptions';
 
@@ -20,6 +24,7 @@ type Props = DefaultProps & {
 };
 
 type State = {
+  elevating: boolean;
   events: WebhookEvent[];
   permissions: Permissions;
 };
@@ -35,6 +40,7 @@ export default class PermissionsObserver extends Component<Props, State> {
     this.state = {
       permissions: this.scopeListToPermissionState(),
       events: this.props.events,
+      elevating: false,
     };
   }
 
@@ -55,14 +61,48 @@ export default class PermissionsObserver extends Component<Props, State> {
 
   onPermissionChange = (permissions: Permissions) => {
     this.setState({permissions});
+    const new_permissions = toResourcePermissions(this.props.scopes);
+
+    let elevating = false;
+    Object.keys(permissions).some((resource_name: string) => {
+      if (
+        comparePermissionLevels(
+          permissions[resource_name],
+          new_permissions[resource_name]
+        ) > 0
+      ) {
+        elevating = true;
+        return true;
+      }
+      return false;
+    });
+
+    this.setState({elevating});
   };
 
   onEventChange = (events: WebhookEvent[]) => {
     this.setState({events});
   };
 
+  renderCallout() {
+    const {elevating} = this.state;
+
+    if (elevating === true) {
+      return (
+        <Alert type="warning" showIcon>
+          {t(
+            'You are going to increase privileges for this integration. Organization members who already had access to the Client Secret may gain extra permissions due to this change. If this is not what you are expecting, consider re-creating the integration.'
+          )}
+        </Alert>
+      );
+    }
+
+    return null;
+  }
+
   render() {
     const {permissions, events} = this.state;
+
     return (
       <Fragment>
         <Panel>
@@ -73,6 +113,7 @@ export default class PermissionsObserver extends Component<Props, State> {
               onChange={this.onPermissionChange}
               appPublished={this.props.appPublished}
             />
+            {this.renderCallout()}
           </PanelBody>
         </Panel>
         <Panel>