]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9448 Sanitize api/qualityprofiles/export
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 22 Jun 2017 11:09:11 +0000 (13:09 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 26 Jun 2017 07:09:42 +0000 (09:09 +0200)
- add parameter 'profile' as the main parameter to identify a quality profile
- deprecate parameters 'name' et 'language'

server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ExportAction.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ExportActionTest.java

index 0b1f1b228fd3f58bb087f4ccd987ac122e57acf6..5194c3c976494da8355edc2124a56a3eb2e8102a 100644 (file)
@@ -45,14 +45,18 @@ import org.sonar.server.util.LanguageParamUtils;
 import org.sonarqube.ws.MediaTypes;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.server.qualityprofile.ws.QProfileWsSupport.createOrganizationParam;
 import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE;
 
 public class ExportAction implements QProfileWsAction {
 
-  private static final String PARAM_PROFILE_NAME = "name";
-  private static final String PARAM_LANGUAGE = "language";
-  private static final String PARAM_FORMAT = "exporterKey";
+  private static final String PARAM_NAME = "name";
+  private static final String PARAM_EXPORTER_KEY = "exporterKey";
 
   private final DbClient dbClient;
   private final QProfileBackuper backuper;
@@ -76,15 +80,25 @@ public class ExportAction implements QProfileWsAction {
       .setResponseExample(getClass().getResource("export-example.xml"))
       .setHandler(this);
 
-    action.createParam(PARAM_PROFILE_NAME)
-      .setDescription("The name of the quality profile to export. If left empty, will export the default profile for the language.")
+    action.createParam(PARAM_PROFILE)
+      .setDescription("Quality profile key")
+      .setSince("6.5")
+      .setExampleValue(UUID_EXAMPLE_01);
+
+    action.createParam(PARAM_NAME)
+      .setDescription("Quality profile name to export. If left empty, the default profile for the language is exported. If this parameter is set, '%s' must not be set.",
+        PARAM_PROFILE)
+      .setDeprecatedSince("6.5")
       .setExampleValue("My Sonar way");
 
     action.createParam(PARAM_LANGUAGE)
-      .setDescription("The language for the quality profile.")
+      .setDescription("Quality profile language.  If this parameter is set, '%s' must not be set.", PARAM_PROFILE)
+      .setDeprecatedSince("6.5")
       .setExampleValue(LanguageParamUtils.getExampleValue(languages))
-      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages))
-      .setRequired(true);
+      .setPossibleValues(LanguageParamUtils.getLanguageKeys(languages));
+
+    createOrganizationParam(action)
+      .setSince("6.4");
 
     Set<String> exporterKeys = Arrays.stream(languages.all())
       .map(language -> exporters.exportersForLanguage(language.getKey()))
@@ -92,26 +106,26 @@ public class ExportAction implements QProfileWsAction {
       .map(ProfileExporter::getKey)
       .collect(MoreCollectors.toSet());
     if (!exporterKeys.isEmpty()) {
-      action.createParam(PARAM_FORMAT)
+      action.createParam(PARAM_EXPORTER_KEY)
         .setDescription("Output format. If left empty, the same format as api/qualityprofiles/backup is used. " +
           "Possible values are described by api/qualityprofiles/exporters.")
         .setPossibleValues(exporterKeys)
         // This deprecated key is only there to be able to deal with redirection from /profiles/export
         .setDeprecatedKey("format", "6.3");
     }
-
-    QProfileWsSupport.createOrganizationParam(action).setSince("6.4");
   }
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    String name = request.param(PARAM_PROFILE_NAME);
-    String language = request.mandatoryParam(PARAM_LANGUAGE);
-    String exporterKey = exporters.exportersForLanguage(language).isEmpty() ? null : request.param(PARAM_FORMAT);
+    String key = request.param(PARAM_PROFILE);
+    String name = request.param(PARAM_NAME);
+    String language = request.param(PARAM_LANGUAGE);
+    checkRequest(key != null ^ language != null, "Either '%s' or '%s' must be provided.", PARAM_PROFILE, PARAM_LANGUAGE);
 
     try (DbSession dbSession = dbClient.openSession(false)) {
       OrganizationDto organization = wsSupport.getOrganizationByKey(dbSession, request.param(PARAM_ORGANIZATION));
-      QProfileDto profile = loadProfile(dbSession, organization, language, name);
+      QProfileDto profile = loadProfile(dbSession, organization, key, language, name);
+      String exporterKey = exporters.exportersForLanguage(profile.getLanguage()).isEmpty() ? null : request.param(PARAM_EXPORTER_KEY);
       writeResponse(dbSession, profile, exporterKey, response);
     }
   }
@@ -131,8 +145,14 @@ public class ExportAction implements QProfileWsAction {
     }
   }
 
-  private QProfileDto loadProfile(DbSession dbSession, OrganizationDto organization, String language, @Nullable String name) {
+  private QProfileDto loadProfile(DbSession dbSession, OrganizationDto organization, @Nullable String key, @Nullable String language, @Nullable String name) {
     QProfileDto profile;
+    if (key != null) {
+      profile = dbClient.qualityProfileDao().selectByUuid(dbSession, key);
+      return checkFound(profile, "Could not find profile with key '%s'", key);
+    }
+
+    checkRequest(language != null, "Parameter '%s' must be provided", PARAM_LANGUAGE);
     if (name == null) {
       // return the default profile
       profile = dbClient.qualityProfileDao().selectDefaultProfile(dbSession, organization, language);
index 397a0b4b76b39c1fa8af06069dd52d1020e6d692..269debcf3beb6fd82e81c1f962c5d01e304813c4 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.language.LanguageTesting;
 import org.sonar.server.organization.TestDefaultOrganizationProvider;
@@ -47,6 +48,8 @@ import org.sonar.server.ws.WsActionTester;
 
 import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE;
 
 public class ExportActionTest {
 
@@ -65,24 +68,30 @@ public class ExportActionTest {
   private QProfileWsSupport wsSupport = new QProfileWsSupport(dbClient, userSession, TestDefaultOrganizationProvider.from(db));
 
   @Test
-  public void test_definition_without_exporters() {
+  public void definition_without_exporters() {
     WebService.Action definition = newWsActionTester().getDef();
 
     assertThat(definition.isPost()).isFalse();
     assertThat(definition.isInternal()).isFalse();
-    assertThat(definition.params()).extracting("key").containsOnly("language", "name", "organization");
+    assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("profile", "language", "name", "organization");
     WebService.Param organizationParam = definition.param("organization");
     assertThat(organizationParam.since()).isEqualTo("6.4");
     assertThat(organizationParam.isInternal()).isTrue();
+    WebService.Param profile = definition.param("profile");
+    assertThat(profile.since()).isEqualTo("6.5");
+    WebService.Param name = definition.param("name");
+    assertThat(name.deprecatedSince()).isEqualTo("6.5");
+    WebService.Param language = definition.param("language");
+    assertThat(language.deprecatedSince()).isEqualTo("6.5");
   }
 
   @Test
-  public void test_definition_with_exporters() {
+  public void definition_with_exporters() {
     WebService.Action definition = newWsActionTester(newExporter("polop"), newExporter("palap")).getDef();
 
     assertThat(definition.isPost()).isFalse();
     assertThat(definition.isInternal()).isFalse();
-    assertThat(definition.params()).extracting("key").containsOnly("language", "name", "organization", "exporterKey");
+    assertThat(definition.params()).extracting("key").containsExactlyInAnyOrder("profile", "language", "name", "organization", "exporterKey");
     WebService.Param exportersParam = definition.param("exporterKey");
     assertThat(exportersParam.possibleValues()).containsOnly("polop", "palap");
     assertThat(exportersParam.deprecatedKey()).isEqualTo("format");
@@ -90,6 +99,46 @@ public class ExportActionTest {
     assertThat(exportersParam.isInternal()).isFalse();
   }
 
+  @Test
+  public void export_profile_with_key() {
+    QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
+
+    WsActionTester tester = newWsActionTester(newExporter("polop"), newExporter("palap"));
+    String result = tester.newRequest()
+      .setParam(PARAM_PROFILE, profile.getKee())
+      .setParam("exporterKey", "polop").execute()
+      .getInput();
+
+    assertThat(result).isEqualTo("Profile " + profile.getLanguage() + "/" + profile.getName() + " exported by polop");
+  }
+
+  @Test
+  public void fail_if_profile_key_is_unknown() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Could not find profile with key 'PROFILE-KEY-404'");
+
+    WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
+    ws.newRequest()
+      .setParam(PARAM_PROFILE, "PROFILE-KEY-404")
+      .setParam("exporterKey", "polop").execute()
+      .getInput();
+  }
+
+  @Test
+  public void fail_if_profile_key_and_language_provided() {
+    QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Either 'profile' or 'language' must be provided.");
+
+    WsActionTester ws = newWsActionTester(newExporter("polop"), newExporter("palap"));
+    ws.newRequest()
+      .setParam(PARAM_PROFILE, profile.getKee())
+      .setParam(PARAM_LANGUAGE, profile.getLanguage())
+      .setParam("exporterKey", "polop").execute()
+      .getInput();
+  }
+
   @Test
   public void export_profile_in_default_organization() {
     QProfileDto profile = createProfile(db.getDefaultOrganization(), false);
@@ -161,6 +210,8 @@ public class ExportActionTest {
 
   @Test
   public void throw_IAE_if_export_with_specified_key_does_not_exist() throws Exception {
+    QProfileDto profile = createProfile(db.getDefaultOrganization(), true);
+
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("Value of parameter 'exporterKey' (unknown) must be one of: [polop, palap]");