From 27d03effdb54942a24c19bfeb49f084bffbcd4d3 Mon Sep 17 00:00:00 2001 From: Antoine Vigneau Date: Mon, 22 Jan 2024 14:29:24 +0100 Subject: [PATCH] SONAR-20934 Propagate useful error messages during GitHub project onboarding --- .../github/ImportGithubProjectActionIT.java | 33 +++++++++++++++--- .../ws/GithubProjectCreatorFactory.java | 12 ++++--- .../ws/GithubProjectCreatorFactoryTest.java | 34 +++++++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java index bf458239a21..e47174d823f 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java @@ -25,16 +25,16 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; -import org.sonar.auth.github.AppInstallationToken; -import org.sonar.auth.github.client.GithubApplicationClient; import org.sonar.alm.client.github.GithubApplicationClientImpl; -import org.sonar.auth.github.GsonRepositoryCollaborator; +import org.sonar.alm.client.github.GithubPermissionConverter; import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; +import org.sonar.auth.github.AppInstallationToken; import org.sonar.auth.github.GitHubSettings; -import org.sonar.alm.client.github.GithubPermissionConverter; +import org.sonar.auth.github.GsonRepositoryCollaborator; import org.sonar.auth.github.GsonRepositoryPermissions; +import org.sonar.auth.github.client.GithubApplicationClient; import org.sonar.core.i18n.I18n; import org.sonar.core.platform.EditionProvider; import org.sonar.core.platform.PlatformEditionProvider; @@ -53,11 +53,11 @@ import org.sonar.db.user.UserDto; import org.sonar.server.almintegration.ws.ImportHelper; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; import org.sonar.server.almsettings.ws.GithubProjectCreatorFactory; -import org.sonar.server.project.ws.ProjectCreator; import org.sonar.server.component.ComponentUpdater; import org.sonar.server.es.EsTester; import org.sonar.server.es.IndexersImpl; import org.sonar.server.es.TestIndexers; +import org.sonar.server.exceptions.BadConfigurationException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.favorite.FavoriteUpdater; @@ -76,11 +76,13 @@ import org.sonar.server.permission.index.PermissionIndexer; import org.sonar.server.project.DefaultBranchNameResolver; import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.Visibility; +import org.sonar.server.project.ws.ProjectCreator; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import org.sonarqube.ws.Projects; +import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNoException; @@ -424,6 +426,27 @@ public class ImportGithubProjectActionIT { .hasMessage("Parameter almSetting is required as there are multiple DevOps Platform configurations."); } + @Test + public void importProject_whenProvisioningIsEnabledButConfigDoesNotAllowAccessToRepo_shouldThrow() { + AlmSettingDto githubAlmSetting = setupUserWithPatAndAlmSettings(); + + when(gitHubSettings.isProvisioningEnabled()).thenReturn(true); + mockGithubDevOpsAppInteractions(); + mockGithubAuthAppInteractions(); + + when(appClient.getInstallationId(any(), any())).thenReturn(Optional.empty()); + + TestRequest request = ws.newRequest() + .setParam(PARAM_ALM_SETTING, githubAlmSetting.getKey()) + .setParam(PARAM_REPOSITORY_KEY, "octocat/" + PROJECT_KEY_NAME); + + assertThatThrownBy(request::execute) + .isInstanceOf(BadConfigurationException.class) + .hasMessage(format("GitHub auto-provisioning is activated. However the repo %s is not in the scope of the authentication application. " + + "The permissions can't be checked, and the project can not be created.", + "octocat/" + PROJECT_KEY_NAME)); + } + @Test public void importProject_whenNoAlmSettingKeyAndOnlyOneConfig_shouldImport() { AlmSettingDto githubAlmSetting = setupUserWithPatAndAlmSettings(); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactory.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactory.java index cf63d1045e4..49a4216af14 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactory.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactory.java @@ -23,19 +23,20 @@ import java.util.Map; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.auth.github.AppInstallationToken; -import org.sonar.auth.github.client.GithubApplicationClient; import org.sonar.alm.client.github.GithubGlobalSettingsValidator; import org.sonar.alm.client.github.GithubPermissionConverter; -import org.sonar.auth.github.GithubAppConfiguration; -import org.sonar.auth.github.security.AccessToken; import org.sonar.api.server.ServerSide; +import org.sonar.auth.github.AppInstallationToken; import org.sonar.auth.github.GitHubSettings; +import org.sonar.auth.github.GithubAppConfiguration; +import org.sonar.auth.github.client.GithubApplicationClient; +import org.sonar.auth.github.security.AccessToken; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; +import org.sonar.server.exceptions.BadConfigurationException; import org.sonar.server.management.ManagedProjectService; import org.sonar.server.permission.PermissionService; import org.sonar.server.permission.PermissionUpdater; @@ -132,7 +133,8 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory if (gitHubSettings.isProvisioningEnabled()) { GithubAppConfiguration githubAppConfiguration = new GithubAppConfiguration(Long.parseLong(gitHubSettings.appId()), gitHubSettings.privateKey(), gitHubSettings.apiURL()); long installationId = findInstallationIdToAccessRepo(githubAppConfiguration, devOpsProjectDescriptor.projectIdentifier()) - .orElseThrow(() -> new IllegalStateException(format("GitHub auto-provisioning is activated. However the repo %s is not in the scope of the authentication application. " + .orElseThrow(() -> new BadConfigurationException("PROJECT", + format("GitHub auto-provisioning is activated. However the repo %s is not in the scope of the authentication application. " + "The permissions can't be checked, and the project can not be created.", devOpsProjectDescriptor.projectIdentifier()))); return Optional.of(generateAppInstallationToken(githubAppConfiguration, installationId)); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactoryTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactoryTest.java index c90c25d4a11..67a169fd365 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactoryTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactoryTest.java @@ -28,16 +28,17 @@ import org.mockito.Answers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.sonar.auth.github.AppInstallationToken; -import org.sonar.auth.github.client.GithubApplicationClient; import org.sonar.alm.client.github.GithubGlobalSettingsValidator; import org.sonar.alm.client.github.GithubPermissionConverter; +import org.sonar.auth.github.AppInstallationToken; import org.sonar.auth.github.GitHubSettings; +import org.sonar.auth.github.client.GithubApplicationClient; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.alm.setting.ALM; import org.sonar.db.alm.setting.AlmSettingDto; import org.sonar.server.almintegration.ws.ProjectKeyGenerator; +import org.sonar.server.exceptions.BadConfigurationException; import org.sonar.server.management.ManagedProjectService; import org.sonar.server.permission.PermissionService; import org.sonar.server.permission.PermissionUpdater; @@ -46,9 +47,11 @@ import org.sonar.server.project.ProjectDefaultVisibility; import org.sonar.server.project.ws.ProjectCreator; import org.sonar.server.user.UserSession; +import static java.lang.String.format; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -163,10 +166,7 @@ public class GithubProjectCreatorFactoryTest { mockSuccessfulGithubInteraction(); when(projectDefaultVisibility.get(any()).isPrivate()).thenReturn(true); - when(gitHubSettings.isProvisioningEnabled()).thenReturn(true); - when(gitHubSettings.appId()).thenReturn("4324"); - when(gitHubSettings.privateKey()).thenReturn("privateKey"); - when(gitHubSettings.apiURL()).thenReturn(GITHUB_API_URL); + mockValidGitHubSettings(); long authAppInstallationId = 32; when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(authAppInstallationId)); @@ -204,6 +204,28 @@ public class GithubProjectCreatorFactoryTest { assertThat(devOpsProjectCreator).usingRecursiveComparison().isEqualTo(expectedGithubProjectCreator); } + @Test + public void getDevOpsProjectCreatorFromImport_whenGitHubConfigDoesNotAllowAccessToRepo_shouldThrow() { + AlmSettingDto mockAlmSettingDto = mockAlmSettingDto(false); + + mockValidGitHubSettings(); + + when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> githubProjectCreatorFactory.getDevOpsProjectCreator(mockAlmSettingDto, appInstallationToken, GITHUB_PROJECT_DESCRIPTOR)) + .isInstanceOf(BadConfigurationException.class) + .hasMessage(format("GitHub auto-provisioning is activated. However the repo %s is not in the scope of the authentication application. " + + "The permissions can't be checked, and the project can not be created.", + GITHUB_REPO_FULL_NAME)); + } + + private void mockValidGitHubSettings() { + when(gitHubSettings.appId()).thenReturn("4324"); + when(gitHubSettings.privateKey()).thenReturn("privateKey"); + when(gitHubSettings.apiURL()).thenReturn(GITHUB_API_URL); + when(gitHubSettings.isProvisioningEnabled()).thenReturn(true); + } + private void mockSuccessfulGithubInteraction() { when(githubApplicationClient.getInstallationId(any(), eq(GITHUB_REPO_FULL_NAME))).thenReturn(Optional.of(APP_INSTALLATION_ID)); when(githubApplicationClient.createAppInstallationToken(any(), eq(APP_INSTALLATION_ID))).thenReturn(Optional.of(appInstallationToken)); -- 2.39.5