Browse Source

SONAR-20700 Add scan permission for the user pushing the report in case auto-provisioning is on

tags/10.3.0.82913
Aurelien Poscia 7 months ago
parent
commit
24cfcf7e1b

+ 2
- 1
server/sonar-webserver-webapi/src/it/java/org/sonar/server/almintegration/ws/github/ImportGithubProjectActionIT.java View File

@@ -135,8 +135,9 @@ public class ImportGithubProjectActionIT {
private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);

private final GithubPermissionConverter githubPermissionConverter = mock();

private final GithubProjectCreatorFactory gitHubProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(),
null, appClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, githubPermissionConverter);
null, appClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, githubPermissionConverter, userPermissionUpdater, permissionService);
private final WsActionTester ws = new WsActionTester(new ImportGithubProjectAction(db.getDbClient(), managedProjectService, userSession,
componentUpdater, importHelper, newCodeDefinitionResolver, defaultBranchNameResolver, gitHubProjectCreatorFactory));


+ 1
- 1
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/BranchReportSubmitterIT.java View File

@@ -108,7 +108,7 @@ public class BranchReportSubmitterIT {
private final BranchSupport branchSupport = spy(new BranchSupport(branchSupportDelegate));

private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(), null,
null, projectDefaultVisibility, null, userSession, componentUpdater, null, null);
null, projectDefaultVisibility, null, userSession, componentUpdater, null, null, null, null);

private final ManagedInstanceService managedInstanceService = mock();
private final ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), branchSupport,

+ 19
- 11
server/sonar-webserver-webapi/src/it/java/org/sonar/server/ce/queue/ReportSubmitterIT.java View File

@@ -63,8 +63,10 @@ import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.favorite.FavoriteUpdater;
import org.sonar.server.management.ManagedInstanceService;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.permission.PermissionTemplateService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChange;
import org.sonar.server.project.DefaultBranchNameResolver;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.project.Visibility;
@@ -77,6 +79,7 @@ import static java.util.stream.IntStream.rangeClosed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -110,18 +113,19 @@ public class ReportSubmitterIT {
private final CeQueue queue = mock(CeQueueImpl.class);
private final TestIndexers projectIndexers = new TestIndexers();
private final PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class);

private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, mock(PermissionUpdater.class), mock(PermissionService.class));
private final BranchSupport ossEditionBranchSupport = new BranchSupport(null);

private final GithubApplicationClient githubApplicationClient = mock();
private final GithubGlobalSettingsValidator githubGlobalSettingsValidator = mock();
private final GitHubSettings gitHubSettings = mock();
private final ProjectKeyGenerator projectKeyGenerator = mock();
private final PermissionUpdater<UserPermissionChange> permissionUpdater = mock();
private PermissionService permissionService = new PermissionServiceImpl(mock());
private final ComponentUpdater componentUpdater = new ComponentUpdater(db.getDbClient(), mock(I18n.class), mock(System2.class), permissionTemplateService,
new FavoriteUpdater(db.getDbClient()), projectIndexers, new SequenceUuidFactory(), defaultBranchNameResolver, mock(PermissionUpdater.class), permissionService);

private final GithubProjectCreatorFactory githubProjectCreatorFactory = new GithubProjectCreatorFactory(db.getDbClient(), githubGlobalSettingsValidator,
githubApplicationClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, null);
githubApplicationClient, projectDefaultVisibility, projectKeyGenerator, userSession, componentUpdater, gitHubSettings, null, permissionUpdater, permissionService);

private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactory = new DelegatingDevOpsProjectCreatorFactory(Set.of(githubProjectCreatorFactory));

private final DevOpsProjectCreatorFactory devOpsProjectCreatorFactorySpy = spy(devOpsProjectCreatorFactory);
@@ -135,6 +139,7 @@ public class ReportSubmitterIT {
public void before() {
when(projectDefaultVisibility.get(any())).thenReturn(Visibility.PUBLIC);
when(defaultBranchNameResolver.getEffectiveMainBranchName()).thenReturn(DEFAULT_MAIN_BRANCH_NAME);
userSession.logIn("login");
}

@Test
@@ -263,9 +268,9 @@ public class ReportSubmitterIT {

@Test
public void submit_whenReportIsForANewProjectWithoutDevOpsMetadata_createsLocalProject() {
userSession.addPermission(PROVISION_PROJECTS);
userSession.addPermission(PROVISION_PROJECTS).addPermission(SCAN);
mockSuccessfulPrepareSubmitCall();
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(DbSession.class), any(), eq(PROJECT_KEY))).thenReturn(true);
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), anyString(), anyString())).thenReturn(true);

underTest.submit(PROJECT_KEY, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8));

@@ -274,7 +279,9 @@ public class ReportSubmitterIT {

@Test
public void submit_whenReportIsForANewProjectWithValidAlmSettingsAutoProvisioningOnAndPermOnGh_createsProjectWithBinding() {
userSession.addPermission(PROVISION_PROJECTS);
UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(PROVISION_PROJECTS).addPermission(SCAN);

when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
mockSuccessfulPrepareSubmitCall();

@@ -288,7 +295,8 @@ public class ReportSubmitterIT {

@Test
public void submit_whenReportIsForANewProjectWithValidAlmSettingsAutoProvisioningOnNoPermOnGhAndGlobalScanPerm_createsProjectWithBinding() {
userSession.addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
UserDto user = db.users().insertUser();
userSession.logIn(user).addPermission(GlobalPermission.SCAN).addPermission(PROVISION_PROJECTS);
when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true);
mockSuccessfulPrepareSubmitCall();

@@ -359,8 +367,8 @@ public class ReportSubmitterIT {
GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(projectDescriptor, almSettingDto, true,
managedInstanceService.isInstanceExternallyManaged(), userSession, mock(),
null);
DevOpsProjectCreator devOpsProjectCreator = spy(
new GithubProjectCreator(db.getDbClient(), githubApplicationClient, null, projectKeyGenerator, componentUpdater, githubProjectCreationParameters));
DevOpsProjectCreator devOpsProjectCreator = spy(new GithubProjectCreator(db.getDbClient(), githubApplicationClient, null, projectKeyGenerator,
componentUpdater, permissionUpdater, permissionService, githubProjectCreationParameters));
doReturn(Optional.of(devOpsProjectCreator)).when(devOpsProjectCreatorFactorySpy).getDevOpsProjectCreator(any(), eq(characteristics));
return devOpsProjectCreator;
}

+ 18
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreator.java View File

@@ -39,11 +39,16 @@ import org.sonar.db.project.CreationMethod;
import org.sonar.db.project.ProjectDto;
import org.sonar.db.provisioning.GithubPermissionsMappingDto;
import org.sonar.db.user.GroupDto;
import org.sonar.db.user.UserIdDto;
import org.sonar.server.almintegration.ws.ProjectKeyGenerator;
import org.sonar.server.common.permission.Operation;
import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentCreationParameters;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.component.NewComponent;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChange;
import org.sonar.server.user.UserSession;

import static java.util.Objects.requireNonNull;
@@ -59,6 +64,8 @@ public class GithubProjectCreator implements DevOpsProjectCreator {
private final GithubPermissionConverter githubPermissionConverter;
private final ProjectKeyGenerator projectKeyGenerator;
private final ComponentUpdater componentUpdater;
private final PermissionUpdater<UserPermissionChange> permissionUpdater;
private final PermissionService permissionService;
private final GithubProjectCreationParameters githubProjectCreationParameters;
private final DevOpsProjectDescriptor devOpsProjectDescriptor;
private final UserSession userSession;
@@ -69,13 +76,16 @@ public class GithubProjectCreator implements DevOpsProjectCreator {
private final AppInstallationToken authAppInstallationToken;

public GithubProjectCreator(DbClient dbClient, GithubApplicationClient githubApplicationClient, GithubPermissionConverter githubPermissionConverter,
ProjectKeyGenerator projectKeyGenerator, ComponentUpdater componentUpdater, GithubProjectCreationParameters githubProjectCreationParameters) {
ProjectKeyGenerator projectKeyGenerator, ComponentUpdater componentUpdater, PermissionUpdater<UserPermissionChange> permissionUpdater, PermissionService permissionService,
GithubProjectCreationParameters githubProjectCreationParameters) {

this.dbClient = dbClient;
this.githubApplicationClient = githubApplicationClient;
this.githubPermissionConverter = githubPermissionConverter;
this.projectKeyGenerator = projectKeyGenerator;
this.componentUpdater = componentUpdater;
this.permissionUpdater = permissionUpdater;
this.permissionService = permissionService;
this.githubProjectCreationParameters = githubProjectCreationParameters;
userSession = githubProjectCreationParameters.userSession();
almSettingDto = githubProjectCreationParameters.almSettingDto();
@@ -156,9 +166,16 @@ public class GithubProjectCreator implements DevOpsProjectCreator {
ComponentCreationData componentCreationData = createProject(dbSession, projectKey, repository, creationMethod);
ProjectDto projectDto = Optional.ofNullable(componentCreationData.projectDto()).orElseThrow();
createProjectAlmSettingDto(dbSession, repository, projectDto, almSettingDto);
addScanPermissionToCurrentUser(dbSession, projectDto);
return componentCreationData;
}

private void addScanPermissionToCurrentUser(DbSession dbSession, ProjectDto projectDto) {
UserIdDto userId = new UserIdDto(requireNonNull(userSession.getUuid()), requireNonNull(userSession.getLogin()));
UserPermissionChange scanPermission = new UserPermissionChange(Operation.ADD, UserRole.SCAN, projectDto, userId, permissionService);
permissionUpdater.apply(dbSession, Set.of(scanPermission));
}

private ComponentCreationData createProject(DbSession dbSession, @Nullable String projectKey, GithubApplicationClient.Repository repository, CreationMethod creationMethod) {
NewComponent projectComponent = newComponentBuilder()
.setKey(Optional.ofNullable(projectKey).orElse(getUniqueProjectKey(repository)))

+ 13
- 4
server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactory.java View File

@@ -37,6 +37,9 @@ 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.component.ComponentUpdater;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChange;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.user.UserSession;

@@ -57,10 +60,13 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory
private final ComponentUpdater componentUpdater;
private final GitHubSettings gitHubSettings;
private final GithubPermissionConverter githubPermissionConverter;
private final PermissionUpdater<UserPermissionChange> permissionUpdater;
private final PermissionService permissionService;

public GithubProjectCreatorFactory(DbClient dbClient, GithubGlobalSettingsValidator githubGlobalSettingsValidator,
GithubApplicationClient githubApplicationClient, ProjectDefaultVisibility projectDefaultVisibility, ProjectKeyGenerator projectKeyGenerator, UserSession userSession,
ComponentUpdater componentUpdater, GitHubSettings gitHubSettings, GithubPermissionConverter githubPermissionConverter) {
ComponentUpdater componentUpdater, GitHubSettings gitHubSettings, GithubPermissionConverter githubPermissionConverter,
PermissionUpdater<UserPermissionChange> permissionUpdater, PermissionService permissionService) {
this.dbClient = dbClient;
this.githubGlobalSettingsValidator = githubGlobalSettingsValidator;
this.githubApplicationClient = githubApplicationClient;
@@ -70,6 +76,8 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory
this.componentUpdater = componentUpdater;
this.gitHubSettings = gitHubSettings;
this.githubPermissionConverter = githubPermissionConverter;
this.permissionUpdater = permissionUpdater;
this.permissionService = permissionService;
}

@Override
@@ -112,7 +120,7 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory
GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
almSettingDto, projectDefaultVisibility.get(dbSession).isPrivate(), gitHubSettings.isProvisioningEnabled(), userSession, appInstallationToken,
authAppInstallationToken.orElse(null));
return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater,
return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, permissionUpdater, permissionService,
githubProjectCreationParameters);
}

@@ -123,7 +131,8 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory
GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
almSettingDto, projectDefaultVisibility.get(dbSession).isPrivate(), gitHubSettings.isProvisioningEnabled(), userSession, accessToken, authAppInstallationToken.orElse(null));
return Optional.of(
new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, githubProjectCreationParameters)
new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, permissionUpdater, permissionService,
githubProjectCreationParameters)
);
}

@@ -132,7 +141,7 @@ public class GithubProjectCreatorFactory implements DevOpsProjectCreatorFactory
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. "
+ "The permissions can't be checked, and the project can not be breated.",
+ "The permissions can't be checked, and the project can not be created.",
devOpsProjectDescriptor.projectIdentifier())));
return Optional.of(generateAppInstallationToken(githubAppConfiguration, installationId));
}

+ 9
- 9
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorFactoryTest.java View File

@@ -39,6 +39,9 @@ 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.component.ComponentUpdater;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChange;
import org.sonar.server.project.ProjectDefaultVisibility;
import org.sonar.server.user.UserSession;

@@ -76,31 +79,28 @@ public class GithubProjectCreatorFactoryTest {
private GithubGlobalSettingsValidator githubGlobalSettingsValidator;
@Mock
private GithubApplicationClient githubApplicationClient;

@Mock
private ComponentUpdater componentUpdater;

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private DbClient dbClient;
@Mock
private UserSession userSession;

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ProjectDefaultVisibility projectDefaultVisibility;

@Mock
private ProjectKeyGenerator projectKeyGenerator;

@Mock
private GitHubSettings gitHubSettings;

@Mock
private GithubPermissionConverter githubPermissionConverter;

@Mock
private AppInstallationToken appInstallationToken;
@Mock
private AppInstallationToken authAppInstallationToken;
@Mock
private PermissionService permissionService;
@Mock
private PermissionUpdater<UserPermissionChange> permissionUpdater;

@InjectMocks
private GithubProjectCreatorFactory githubProjectCreatorFactory;
@@ -217,10 +217,10 @@ public class GithubProjectCreatorFactoryTest {
AppInstallationToken authAppInstallToken = isInstanceManaged ? authAppInstallationToken : null;
GithubProjectCreationParameters githubProjectCreationParameters = new GithubProjectCreationParameters(devOpsProjectDescriptor,
almSettingDto, projectsArePrivateByDefault, isInstanceManaged, userSession, appInstallationToken, authAppInstallToken);
return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, githubProjectCreationParameters);
return new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater, permissionUpdater, permissionService,
githubProjectCreationParameters);
}


private AlmSettingDto mockAlmSettingDto(boolean repoAccess) {
AlmSettingDto almSettingDto = mock();
when(almSettingDto.getUrl()).thenReturn(repoAccess ? GITHUB_PROJECT_DESCRIPTOR.url() : "anotherUrl");

+ 20
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/almsettings/ws/GithubProjectCreatorTest.java View File

@@ -20,6 +20,7 @@
package org.sonar.server.almsettings.ws;

import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.Set;
import org.junit.Before;
@@ -53,6 +54,10 @@ import org.sonar.server.component.ComponentCreationData;
import org.sonar.server.component.ComponentCreationParameters;
import org.sonar.server.component.ComponentUpdater;
import org.sonar.server.component.NewComponent;
import org.sonar.server.permission.PermissionService;
import org.sonar.server.permission.PermissionServiceImpl;
import org.sonar.server.permission.PermissionUpdater;
import org.sonar.server.permission.UserPermissionChange;
import org.sonar.server.user.UserSession;

import static java.util.Objects.requireNonNull;
@@ -98,6 +103,9 @@ public class GithubProjectCreatorTest {
private UserSession userSession;
@Mock
private AlmSettingDto almSettingDto;
private PermissionService permissionService = new PermissionServiceImpl(mock());
@Mock
private PermissionUpdater<UserPermissionChange> permissionUpdater;

private GithubProjectCreator githubProjectCreator;

@@ -121,7 +129,7 @@ public class GithubProjectCreatorTest {
when(githubProjectCreationParameters.almSettingDto()).thenReturn(almSettingDto);

githubProjectCreator = new GithubProjectCreator(dbClient, githubApplicationClient, githubPermissionConverter, projectKeyGenerator, componentUpdater,
githubProjectCreationParameters);
permissionUpdater, permissionService, githubProjectCreationParameters);
}

@Test
@@ -296,6 +304,10 @@ public class GithubProjectCreatorTest {
assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);
}

@Captor
private ArgumentCaptor<Collection<UserPermissionChange>> permissionChangesCaptor;

@Test
public void createProjectAndBindToDevOpsPlatformFromApi_whenRepoFoundOnGitHubAutoProvisioningOnAndRepoPrivate_successfullyCreatesProject() {
// given
when(githubProjectCreationParameters.projectsArePrivateByDefault()).thenReturn(true);
@@ -319,6 +331,13 @@ public class GithubProjectCreatorTest {
assertThat(componentCreationParameters.isManaged()).isTrue();
assertThat(componentCreationParameters.newComponent().isPrivate()).isTrue();

verify(permissionUpdater).apply(any(), permissionChangesCaptor.capture());
UserPermissionChange permissionChange = permissionChangesCaptor.getValue().iterator().next();
assertThat(permissionChange.getUserId().getUuid()).isEqualTo(userSession.getUuid());
assertThat(permissionChange.getUserId().getLogin()).isEqualTo(userSession.getLogin());
assertThat(permissionChange.getPermission()).isEqualTo(UserRole.SCAN);
assertThat(permissionChange.getProjectUuid()).isEqualTo(actualComponentCreationData.projectDto().getUuid());

verify(projectAlmSettingDao).insertOrUpdate(any(), projectAlmSettingDtoCaptor.capture(), eq(ALM_SETTING_KEY), eq(REPOSITORY_NAME), eq(projectKey));
ProjectAlmSettingDto projectAlmSettingDto = projectAlmSettingDtoCaptor.getValue();
assertAlmSettingsDtoContainsCorrectInformation(almSettingDto, requireNonNull(componentCreationData.projectDto()), projectAlmSettingDto);

Loading…
Cancel
Save