]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-19790 handled managed projects /api/permissions/[bulk_]apply_template
authorAurelien Poscia <aurelien.poscia@sonarsource.com>
Fri, 14 Jul 2023 09:45:49 +0000 (11:45 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 18 Jul 2023 20:03:22 +0000 (20:03 +0000)
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/ApplyTemplateActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/template/ApplyTemplateAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java

index fbd658b8eb646ef8dfd20af618b978082bbd5f8b..594d47573bfc6deb38958e211b54f095d5753c45 100644 (file)
@@ -38,6 +38,8 @@ import org.sonar.server.es.TestIndexers;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceChecker;
+import org.sonar.server.management.ManagedProjectService;
 import org.sonar.server.permission.DefaultTemplatesResolver;
 import org.sonar.server.permission.DefaultTemplatesResolverImpl;
 import org.sonar.server.permission.PermissionTemplateService;
@@ -46,6 +48,10 @@ import org.sonar.server.ws.TestRequest;
 
 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.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.VIEW;
@@ -72,9 +78,12 @@ public class ApplyTemplateActionIT extends BasePermissionWsIT<ApplyTemplateActio
   private final PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
     new TestIndexers(), userSession, defaultTemplatesResolver, new SequenceUuidFactory());
 
+  private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
+  private final ManagedInstanceChecker managedInstanceChecker = new ManagedInstanceChecker(null, managedProjectService);
+
   @Override
   protected ApplyTemplateAction buildWsAction() {
-    return new ApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport());
+    return new ApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), managedInstanceChecker);
   }
 
   @Before
@@ -186,6 +195,19 @@ public class ApplyTemplateActionIT extends BasePermissionWsIT<ApplyTemplateActio
       .hasMessage("Project id or project key can be provided, not both.");
   }
 
+  @Test
+  public void fail_when_project_is_managed() {
+    loginAsAdmin();
+
+    when(managedProjectService.isProjectManaged(any(), eq(project.getUuid()))).thenReturn(true);
+
+    String templateUuid = template1.getUuid();
+    String projectUuid = project.getUuid();
+    assertThatThrownBy(() -> newRequest(templateUuid, projectUuid, null))
+      .isInstanceOf(BadRequestException.class)
+      .hasMessage("Operation not allowed when the project is externally managed.");
+  }
+
   @Test
   public void fail_when_not_admin() {
     userSession.logIn().addPermission(SCAN);
index 1fa591ec7e34dacbda8ae59ad25aaf25664e6a40..f6ad527c94ce3035ccdc3f95df0eb80ba34f4fbb 100644 (file)
@@ -44,6 +44,7 @@ import org.sonar.server.es.TestIndexers;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.l18n.I18nRule;
+import org.sonar.server.management.ManagedProjectService;
 import org.sonar.server.permission.DefaultTemplatesResolver;
 import org.sonar.server.permission.DefaultTemplatesResolverImpl;
 import org.sonar.server.permission.PermissionTemplateService;
@@ -51,6 +52,10 @@ import org.sonar.server.permission.ws.BasePermissionWsIT;
 
 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.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.sonar.api.resources.Qualifiers.APP;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.VIEW;
@@ -75,11 +80,14 @@ public class BulkApplyTemplateActionIT extends BasePermissionWsIT<BulkApplyTempl
   private final ResourceTypesRule resourceTypesRule = new ResourceTypesRule().setRootQualifiers(PROJECT, VIEW, APP);
   private final DefaultTemplatesResolver defaultTemplatesResolver = new DefaultTemplatesResolverImpl(db.getDbClient(), resourceTypesRule);
 
+  private final ManagedProjectService managedProjectService = mock(ManagedProjectService.class);
+
   @Override
   protected BulkApplyTemplateAction buildWsAction() {
     PermissionTemplateService permissionTemplateService = new PermissionTemplateService(db.getDbClient(),
       indexers, userSession, defaultTemplatesResolver, new SequenceUuidFactory());
-    return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes());
+    return new BulkApplyTemplateAction(db.getDbClient(), userSession, permissionTemplateService, newPermissionWsSupport(), new I18nRule(), newRootResourceTypes(),
+      managedProjectService);
   }
 
   @Before
@@ -291,6 +299,22 @@ public class BulkApplyTemplateActionIT extends BasePermissionWsIT<BulkApplyTempl
     assertNoPermissionOnEntity(publicProject);
   }
 
+  @Test
+  public void apply_template_filters_out_managed_projects() {
+    ProjectDto managedProject = db.components().insertPrivateProject().getProjectDto();
+    ProjectDto nonManagedProject = db.components().insertPrivateProject().getProjectDto();
+    when(managedProjectService.isProjectManaged(any(), eq(managedProject.getUuid()))).thenReturn(true);
+    loginAsAdmin();
+
+    newRequest()
+      .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
+      .setParam(PARAM_VISIBILITY, "private")
+      .execute();
+
+    assertNoPermissionOnEntity(managedProject);
+    assertTemplate1AppliedToPrivateProject(nonManagedProject);
+  }
+
   @Test
   public void fail_if_no_template_parameter() {
     loginAsAdmin();
index f7e4995fd46cb1fdc49dd2c715a00d99f1cfa08c..0e90558f9dc6990f90ed77c94fb345220a4db77a 100644 (file)
@@ -32,6 +32,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.permission.template.PermissionTemplateDto;
 import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.management.ManagedInstanceChecker;
 import org.sonar.server.permission.PermissionTemplateService;
 import org.sonar.server.permission.ws.PermissionWsSupport;
 import org.sonar.server.permission.ws.PermissionsWsAction;
@@ -53,12 +54,15 @@ public class ApplyTemplateAction implements PermissionsWsAction {
   private final PermissionTemplateService permissionTemplateService;
   private final PermissionWsSupport wsSupport;
 
+  private final ManagedInstanceChecker managedInstanceChecker;
+
   public ApplyTemplateAction(DbClient dbClient, UserSession userSession, PermissionTemplateService permissionTemplateService,
-    PermissionWsSupport wsSupport) {
+    PermissionWsSupport wsSupport, ManagedInstanceChecker managedInstanceChecker) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.permissionTemplateService = permissionTemplateService;
     this.wsSupport = wsSupport;
+    this.managedInstanceChecker = managedInstanceChecker;
   }
 
   private static ApplyTemplateRequest toApplyTemplateWsRequest(Request request) {
@@ -99,6 +103,9 @@ public class ApplyTemplateAction implements PermissionsWsAction {
       EntityDto entityDto = getEntityByKeyOrUuid(request.getProjectId(), request.getProjectKey(), dbSession);
       checkGlobalAdmin(userSession);
 
+      if (entityDto.isProject()) {
+        managedInstanceChecker.throwIfProjectIsManaged(dbSession, entityDto.getUuid());
+      }
       permissionTemplateService.applyAndCommit(dbSession, template, Collections.singletonList(entityDto));
     }
   }
index b71db9839bfc56324a61471e8f8c11023fdc2299..62df55b54b72cb096a03e813e5c3fe9c98b5b64b 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.permission.ws.template;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
@@ -40,6 +41,7 @@ import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentQuery;
 import org.sonar.db.entity.EntityDto;
 import org.sonar.db.permission.template.PermissionTemplateDto;
+import org.sonar.server.management.ManagedProjectService;
 import org.sonar.server.permission.PermissionTemplateService;
 import org.sonar.server.permission.ws.PermissionWsSupport;
 import org.sonar.server.permission.ws.PermissionsWsAction;
@@ -56,8 +58,8 @@ import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobal
 import static org.sonar.server.permission.ws.template.WsTemplateRef.newTemplateRef;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
-import static org.sonar.server.ws.WsParameterBuilder.createRootQualifiersParameter;
 import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
+import static org.sonar.server.ws.WsParameterBuilder.createRootQualifiersParameter;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
 import static org.sonarqube.ws.client.project.ProjectsWsParameters.PARAM_ANALYZED_BEFORE;
@@ -74,21 +76,23 @@ public class BulkApplyTemplateAction implements PermissionsWsAction {
   private final PermissionWsSupport wsSupport;
   private final I18n i18n;
   private final ResourceTypes resourceTypes;
+  private final ManagedProjectService managedProjectService;
 
   public BulkApplyTemplateAction(DbClient dbClient, UserSession userSession, PermissionTemplateService permissionTemplateService, PermissionWsSupport wsSupport, I18n i18n,
-    ResourceTypes resourceTypes) {
+    ResourceTypes resourceTypes, ManagedProjectService managedProjectService) {
     this.dbClient = dbClient;
     this.userSession = userSession;
     this.permissionTemplateService = permissionTemplateService;
     this.wsSupport = wsSupport;
     this.i18n = i18n;
     this.resourceTypes = resourceTypes;
+    this.managedProjectService = managedProjectService;
   }
 
   @Override
   public void define(WebService.NewController context) {
     WebService.NewAction action = context.createAction("bulk_apply_template")
-      .setDescription("Apply a permission template to several projects.<br />" +
+      .setDescription("Apply a permission template to several components. Managed projects will be ignored.<br />" +
         "The template id or name must be provided.<br />" +
         "Requires the following permission: 'Administer System'.")
       .setPost(true)
@@ -119,7 +123,7 @@ public class BulkApplyTemplateAction implements PermissionsWsAction {
 
     action.createParam(PARAM_VISIBILITY)
       .setDescription("Filter the projects that should be visible to everyone (%s), or only specific user/groups (%s).<br/>" +
-        "If no visibility is specified, the default project visibility will be used.",
+          "If no visibility is specified, the default project visibility will be used.",
         Visibility.PUBLIC.getLabel(), Visibility.PRIVATE.getLabel())
       .setRequired(false)
       .setInternal(true)
@@ -154,9 +158,12 @@ public class BulkApplyTemplateAction implements PermissionsWsAction {
       ComponentQuery componentQuery = buildDbQuery(request);
       List<ComponentDto> components = dbClient.componentDao().selectByQuery(dbSession, componentQuery, 0, Integer.MAX_VALUE);
 
-      List<EntityDto> entities = dbClient.entityDao().selectByKeys(dbSession, components.stream()
+      Set<String> entityUuids = components.stream()
         .map(ComponentDto::getKey)
-        .collect(Collectors.toSet()));
+        .collect(Collectors.toSet());
+      List<EntityDto> entities = dbClient.entityDao().selectByKeys(dbSession, entityUuids).stream()
+        .filter(entity -> !managedProjectService.isProjectManaged(dbSession, entity.getUuid()))
+        .toList();
 
       permissionTemplateService.applyAndCommit(dbSession, template, entities);
     }