]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22596 Inform Admins about GitLab auto-provisioning
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Tue, 23 Jul 2024 14:57:02 +0000 (16:57 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 25 Jul 2024 20:02:51 +0000 (20:02 +0000)
server/sonar-web/src/main/js/api/mocks/SettingsServiceMock.ts
server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GitHubAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Github-it.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/__tests__/Authentication-Gitlab-it.tsx
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index a281f8b2501bdb37d0fc9cac7c8a9e71f3df800a..cd33aaa83e1604b7f2d927caf9d4cf72745909c4 100644 (file)
@@ -224,6 +224,10 @@ export default class SettingsServiceMock {
       this.#settingValues = this.#settingValues.filter(
         (s) => s.key !== 'sonar.auth.github.userConsentForPermissionProvisioningRequired',
       );
+    } else if (data.keys === 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired') {
+      this.#settingValues = this.#settingValues.filter(
+        (s) => s.key !== 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired',
+      );
     } else if (definition.type === SettingType.PROPERTY_SET) {
       const fieldValues: Dict<string>[] = [];
       if (setting) {
index 1f78fefae0e11c3cd61706b3cf7d2dca77a6931a..0e18dea9b7b6c6404052c4c03ba0cc9258d80584 100644 (file)
@@ -25,44 +25,73 @@ import * as React from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
 import { DocLink } from '../../../../helpers/doc-links';
-import {
-  useSearchGitHubConfigurationsQuery,
-  useUpdateGitHubConfigurationMutation,
-} from '../../../../queries/dop-translation';
-import { ProvisioningType } from '../../../../types/provisioning';
+import { useUpdateGitHubConfigurationMutation } from '../../../../queries/dop-translation';
+import { useUpdateGitLabConfigurationMutation } from '../../../../queries/identity-provider/gitlab';
+import { useGetValueQuery, useResetSettingsMutation } from '../../../../queries/settings';
+import { GitHubConfigurationResponse } from '../../../../types/dop-translation';
+import { GitlabConfiguration, ProvisioningType } from '../../../../types/provisioning';
 
-export default function AutoProvisioningConsent() {
+const CONSENT_SETTING_KEY = 'sonar.auth.gitlab.userConsentForPermissionProvisioningRequired';
+
+interface Props {
+  githubConfiguration?: GitHubConfigurationResponse;
+  gitlabConfiguration?: GitlabConfiguration;
+}
+
+export default function AutoProvisioningConsent(props: Readonly<Props>) {
   const { formatMessage } = useIntl();
-  const { data: list } = useSearchGitHubConfigurationsQuery();
-  const gitHubConfiguration = list?.githubConfigurations[0];
+  const { githubConfiguration, gitlabConfiguration } = props;
 
-  const { mutate: updateConfig } = useUpdateGitHubConfigurationMutation();
+  const { mutate: updateGithubConfig } = useUpdateGitHubConfigurationMutation();
+  const { mutate: updateGitlabConfig } = useUpdateGitLabConfigurationMutation();
+  const { data: userConsent } = useGetValueQuery(CONSENT_SETTING_KEY);
+  const { mutateAsync: resetSettingValue } = useResetSettingsMutation();
 
-  if (gitHubConfiguration?.userConsentRequiredAfterUpgrade !== true) {
+  if (
+    (githubConfiguration?.userConsentRequiredAfterUpgrade !== true &&
+      gitlabConfiguration === undefined) ||
+    (!userConsent && githubConfiguration === undefined)
+  ) {
     return null;
   }
 
   const header = formatMessage({
-    id: 'settings.authentication.github.confirm_auto_provisioning.header',
+    id: 'settings.authentication.confirm_auto_provisioning.header',
   });
 
   const onClickAutoProvisioning = () => {
-    updateConfig({
-      id: gitHubConfiguration.id,
-      gitHubConfiguration: {
-        userConsentRequiredAfterUpgrade: false,
-      },
-    });
+    if (githubConfiguration) {
+      updateGithubConfig({
+        id: githubConfiguration.id,
+        gitHubConfiguration: {
+          userConsentRequiredAfterUpgrade: false,
+        },
+      });
+    }
+    if (gitlabConfiguration) {
+      resetSettingValue({ keys: [CONSENT_SETTING_KEY] });
+    }
   };
 
   const onClickJitProvisioning = () => {
-    updateConfig({
-      id: gitHubConfiguration.id,
-      gitHubConfiguration: {
-        provisioningType: ProvisioningType.jit,
-        userConsentRequiredAfterUpgrade: false,
-      },
-    });
+    if (githubConfiguration) {
+      updateGithubConfig({
+        id: githubConfiguration.id,
+        gitHubConfiguration: {
+          provisioningType: ProvisioningType.jit,
+          userConsentRequiredAfterUpgrade: false,
+        },
+      });
+    }
+    if (gitlabConfiguration) {
+      updateGitlabConfig({
+        id: gitlabConfiguration.id,
+        data: {
+          provisioningType: ProvisioningType.jit,
+        },
+      });
+      resetSettingValue({ keys: [CONSENT_SETTING_KEY] });
+    }
   };
 
   return (
@@ -71,14 +100,19 @@ export default function AutoProvisioningConsent() {
       <Modal.Body>
         <FormattedMessage
           tagName="p"
-          id="settings.authentication.github.confirm_auto_provisioning.description1"
+          id="settings.authentication.confirm_auto_provisioning.description1"
         />
         <FormattedMessage
-          id="settings.authentication.github.confirm_auto_provisioning.description2"
+          id="settings.authentication.confirm_auto_provisioning.description2"
           tagName="p"
           values={{
+            alm: githubConfiguration
+              ? formatMessage({ id: 'alm.github' })
+              : formatMessage({ id: 'alm.gitlab' }),
             documentation: (
-              <DocumentationLink to={DocLink.AlmGitHubAuth}>
+              <DocumentationLink
+                to={githubConfiguration ? DocLink.AlmGitHubAuth : DocLink.AlmGitLabAuth}
+              >
                 <FormattedMessage id="documentation" />
               </DocumentationLink>
             ),
@@ -86,18 +120,18 @@ export default function AutoProvisioningConsent() {
         />
         <FormattedMessage
           tagName="p"
-          id="settings.authentication.github.confirm_auto_provisioning.question"
+          id="settings.authentication.confirm_auto_provisioning.question"
         />
       </Modal.Body>
       <Modal.Footer
         primaryButton={
           <Button onClick={onClickAutoProvisioning}>
-            <FormattedMessage id="settings.authentication.github.confirm_auto_provisioning.continue" />
+            <FormattedMessage id="settings.authentication.confirm_auto_provisioning.continue" />
           </Button>
         }
         secondaryButton={
           <Button onClick={onClickJitProvisioning}>
-            <FormattedMessage id="settings.authentication.github.confirm_auto_provisioning.switch_jit" />
+            <FormattedMessage id="settings.authentication.confirm_auto_provisioning.switch_jit" />
           </Button>
         }
       />
index 171836a291157d29ddd27e88bb7617fbe915d27d..90b6bbcad3f42c31a54d63bcfe83165791d090ec 100644 (file)
@@ -376,7 +376,7 @@ export default function GitHubAuthenticationTab() {
           />
         )}
 
-        <AutoProvisioningConsent />
+        <AutoProvisioningConsent githubConfiguration={gitHubConfiguration} />
       </div>
     </Spinner>
   );
index 51b955320a86d91faab5391709a6ce748d5c56c9..59562f8facdafc56cfcf32253c31ebe31d854e20 100644 (file)
@@ -39,6 +39,7 @@ import { GitLabConfigurationUpdateBody, ProvisioningType } from '../../../../typ
 import { DefinitionV2, SettingType } from '../../../../types/settings';
 import { Provider } from '../../../../types/types';
 import AuthenticationFormField from './AuthenticationFormField';
+import AutoProvisioningConsent from './AutoProvisionningConsent';
 import ConfigurationDetails from './ConfigurationDetails';
 import ConfirmProvisioningModal from './ConfirmProvisioningModal';
 import GitLabConfigurationForm from './GitLabConfigurationForm';
@@ -392,6 +393,7 @@ export default function GitLabAuthenticationTab() {
           onClose={() => setOpenForm(false)}
         />
       )}
+      <AutoProvisioningConsent gitlabConfiguration={configuration} />
     </Spinner>
   );
 }
index 7b69d09c709a599cbdbda16c5df868b4b6bc60fc..5e75ebb38af21939a5573337d6732bf51b5ba576 100644 (file)
@@ -196,13 +196,13 @@ const ui = {
     name: 'settings.authentication.github.configuration.validation.details.title',
   }),
   continueAutoButton: byRole('button', {
-    name: 'settings.authentication.github.confirm_auto_provisioning.continue',
+    name: 'settings.authentication.confirm_auto_provisioning.continue',
   }),
   switchJitButton: byRole('button', {
-    name: 'settings.authentication.github.confirm_auto_provisioning.switch_jit',
+    name: 'settings.authentication.confirm_auto_provisioning.switch_jit',
   }),
   consentDialog: byRole('dialog', {
-    name: 'settings.authentication.github.confirm_auto_provisioning.header',
+    name: 'settings.authentication.confirm_auto_provisioning.header',
   }),
   getConfigDetailsTitle: () => ui.configDetailsDialog.byRole('heading').get(),
   getOrgs: () => ui.configDetailsDialog.byRole('listitem').getAll(),
index da293414c1cb251cf8182e9cc1c3e10ff740fd8d..186bbc3ab962593057d5799da93cff5388a75e2c 100644 (file)
@@ -144,6 +144,15 @@ const ui = {
   testConfiguration: glContainer.byRole('button', {
     name: 'settings.authentication.configuration.test',
   }),
+  continueAutoButton: byRole('button', {
+    name: 'settings.authentication.confirm_auto_provisioning.continue',
+  }),
+  switchJitButton: byRole('button', {
+    name: 'settings.authentication.confirm_auto_provisioning.switch_jit',
+  }),
+  consentDialog: byRole('dialog', {
+    name: 'settings.authentication.confirm_auto_provisioning.header',
+  }),
 };
 
 it('should create a Gitlab configuration and disable it with proper validation', async () => {
@@ -581,6 +590,50 @@ describe('Gitlab Provisioning', () => {
     await user.click(ui.disableConfigButton.get());
     expect(ui.gitlabConfigurationStatus.query()).not.toBeInTheDocument();
   });
+
+  it('should display a modal if user was already using auto and continue using auto provisioning', async () => {
+    const user = userEvent.setup();
+
+    settingsHandler.set('sonar.auth.gitlab.userConsentForPermissionProvisioningRequired', '');
+    handler.setGitlabConfigurations([
+      mockGitlabConfiguration({
+        allowUsersToSignUp: false,
+        enabled: true,
+        provisioningType: ProvisioningType.auto,
+        allowedGroups: ['D12'],
+        isProvisioningTokenSet: true,
+      }),
+    ]);
+    renderAuthentication([Feature.GitlabProvisioning]);
+
+    expect(await ui.consentDialog.find()).toBeInTheDocument();
+    await user.click(ui.continueAutoButton.get());
+
+    expect(await ui.autoProvisioningRadioButton.find()).toBeChecked();
+    expect(ui.consentDialog.query()).not.toBeInTheDocument();
+  });
+
+  it('should display a modal if user was already using auto and switch to JIT', async () => {
+    const user = userEvent.setup();
+
+    settingsHandler.set('sonar.auth.gitlab.userConsentForPermissionProvisioningRequired', '');
+    handler.setGitlabConfigurations([
+      mockGitlabConfiguration({
+        allowUsersToSignUp: false,
+        enabled: true,
+        provisioningType: ProvisioningType.auto,
+        allowedGroups: ['D12'],
+        isProvisioningTokenSet: true,
+      }),
+    ]);
+    renderAuthentication([Feature.GitlabProvisioning]);
+
+    expect(await ui.consentDialog.find()).toBeInTheDocument();
+    await user.click(ui.switchJitButton.get());
+
+    expect(await ui.jitProvisioningRadioButton.find()).toBeChecked();
+    expect(ui.consentDialog.query()).not.toBeInTheDocument();
+  });
 });
 
 function renderAuthentication(features: Feature[] = []) {
index 05b973f80b9197e828e5d723211f225a01776e05..044cee3790fbf55baf0b56d3b9e2b0290e62c939 100644 (file)
@@ -1538,6 +1538,12 @@ settings.authentication.form.provisioning=Provisioning
 settings.authentication.form.provisioning_at_login=Just-in-Time user and group provisioning (default)
 settings.authentication.form.other_provisioning_enabled=Already enabled for another provider.  Only one identity provider can have automatic users and groups provisioning enabled.
 settings.authentication.form.settings.save_success=Settings saved successfully.
+settings.authentication.confirm_auto_provisioning.header=Confirm the provisioning method
+settings.authentication.confirm_auto_provisioning.description1=Automatic user and group provisioning is currently suspended.
+settings.authentication.confirm_auto_provisioning.description2=This provisioning method has been enhanced. It now includes the synchronization of user permissions and project visibility from {alm}. For more details, please refer to the {documentation}.
+settings.authentication.confirm_auto_provisioning.question=Which provisioning method would you like to use?
+settings.authentication.confirm_auto_provisioning.continue=Automatic user, group, and permission provisioning
+settings.authentication.confirm_auto_provisioning.switch_jit=Just-in-Time user and group provisioning
 
 # GITHUB
 settings.authentication.github.form.create=New GitHub Configuration
@@ -1548,12 +1554,6 @@ settings.authentication.github.confirm.JIT=Switch to Just-in-Time provisioning
 settings.authentication.github.confirm.insecure=Potentially insecure configuration
 settings.authentication.github.confirm.AUTO_PROVISIONING.description=Once you transition to automatic provisioning, groups, users, group memberships, and permissions on GitHub projects will be inherited from GitHub. You will no longer have the ability to edit them within SonarQube. Do you want to proceed with this change?
 settings.authentication.github.confirm.JIT.description=Switching to Just-in-Time provisioning removes the automatic synchronization of users, groups, and group memberships. Users are provisioned and group memberships are updated only at user login. Are you sure?
-settings.authentication.github.confirm_auto_provisioning.header=Confirm the provisioning method
-settings.authentication.github.confirm_auto_provisioning.description1=Automatic user and group provisioning is currently suspended.
-settings.authentication.github.confirm_auto_provisioning.description2=This provisioning method has been enhanced. It now includes the synchronization of user permissions and project visibility from GitHub. For more details, please refer to the {documentation}.
-settings.authentication.github.confirm_auto_provisioning.question=Which provisioning method would you like to use?
-settings.authentication.github.confirm_auto_provisioning.continue=Automatic user, group, and permission provisioning
-settings.authentication.github.confirm_auto_provisioning.switch_jit=Just-in-Time user and group provisioning
 settings.authentication.github.provisioning_change.confirm_changes=Confirm changes
 settings.authentication.github.provisioning_change.insecure_config=Please be aware that your configuration is potentially insecure because you didn't add any organization to the allowlist. If your GitHub App is public, anyone can install it and gain access to your instance.
 settings.authentication.github.configuration=GitHub Configuration