diff options
Diffstat (limited to 'server')
25 files changed, 177 insertions, 64 deletions
diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java index 4ca698cd35d..43ef628cfdd 100644 --- a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/gitlab/GitlabApplicationClientTest.java @@ -484,7 +484,8 @@ public class GitlabApplicationClientTest { .hasMessage("Could not validate GitLab read permission. Got an unexpected answer."); assertThat(logTester.logs(Level.INFO).get(0)) .contains("Gitlab API call to [" + server.url("/projects") + "] " + - "failed with error message : [Failed to connect to " + server.getHostName()); + "failed with error message : [Failed to connect to ") + .contains(server.getHostName()); } @Test @@ -496,7 +497,8 @@ public class GitlabApplicationClientTest { .hasMessage("Could not validate GitLab token. Got an unexpected answer."); assertThat(logTester.logs(Level.INFO).get(0)) .contains("Gitlab API call to [" + server.url("user") + "] " + - "failed with error message : [Failed to connect to " + server.getHostName()); + "failed with error message : [Failed to connect to ") + .contains(server.getHostName()); } @Test @@ -508,7 +510,8 @@ public class GitlabApplicationClientTest { .hasMessage("Could not validate GitLab write permission. Got an unexpected answer."); assertThat(logTester.logs(Level.INFO).get(0)) .contains("Gitlab API call to [" + server.url("/markdown") + "] " + - "failed with error message : [Failed to connect to " + server.getHostName()); + "failed with error message : [Failed to connect to ") + .contains(server.getHostName()); } @Test @@ -520,7 +523,8 @@ public class GitlabApplicationClientTest { .hasMessageContaining("Failed to connect to"); assertThat(logTester.logs(Level.INFO).get(0)) .contains("Gitlab API call to [" + server.url("/projects/0") + "] " + - "failed with error message : [Failed to connect to " + server.getHostName()); + "failed with error message : [Failed to connect to ") + .contains( server.getHostName()); } @Test @@ -529,7 +533,8 @@ public class GitlabApplicationClientTest { assertThatThrownBy(() -> underTest.getBranches(gitlabUrl, "token", 0L)) .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Failed to connect to " + server.getHostName()); + .hasMessageContaining("Failed to connect to ") + .hasMessageContaining(server.getHostName()); assertThat(logTester.logs(Level.INFO).get(0)) .contains("Gitlab API call to [" + server.url("/projects/0/repository/branches") + "] " + "failed with error message : [Failed to connect to " + server.getHostName()); @@ -546,7 +551,8 @@ public class GitlabApplicationClientTest { .contains( "Gitlab API call to [" + server.url("/projects?archived=false&simple=true&membership=true&order_by=name&sort=asc&search=&page=1&per_page=1") + "] " + - "failed with error message : [Failed to connect to " + server.getHostName()); + "failed with error message : [Failed to connect to ") + .contains( server.getHostName()); } @Test diff --git a/server/sonar-db-dao/src/it/java/org/sonar/db/report/RegulatoryReportDaoIT.java b/server/sonar-db-dao/src/it/java/org/sonar/db/report/RegulatoryReportDaoIT.java index 3b3d9ca49cc..88440d187a1 100644 --- a/server/sonar-db-dao/src/it/java/org/sonar/db/report/RegulatoryReportDaoIT.java +++ b/server/sonar-db-dao/src/it/java/org/sonar/db/report/RegulatoryReportDaoIT.java @@ -90,7 +90,7 @@ class RegulatoryReportDaoIT { List<IssueFindingDto> issues = new ArrayList<>(); underTest.scrollIssues(db.getSession(), PROJECT_UUID, result -> issues.add(result.getResultObject())); - assertThat(issues).extracting(IssueFindingDto::getKey).containsOnly(issue1.getKey(), issue2.getKey(), issue3.getKey()); + assertThat(issues).extracting(IssueFindingDto::getKey).containsOnly(issue1.getKey(), issue2.getKey(), issue3.getKey(), issueCodeSmell.getKey()); // check fields IssueFindingDto issue = issues.stream().filter(i -> i.getKey().equals(issue1.getKey())).findFirst().get(); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateFindingDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateFindingDto.java index ebefc919835..17e310f3887 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateFindingDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateFindingDto.java @@ -27,6 +27,7 @@ public class QualityGateFindingDto { private String operator = null; private String valueType = null; private String errorThreshold = null; + private String qualityGateName = null; public String getDescription() { return description; @@ -52,6 +53,10 @@ public class QualityGateFindingDto { return errorThreshold; } + public String getQualityGateName() { + return qualityGateName; + } + private String getOperator() { return operator; } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml index d4dd06bf35d..16df5308d01 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateMapper.xml @@ -7,6 +7,12 @@ </sql> <sql id="qualityGateFindingColumns"> + <!-- + If a row's columns are all `null`, MyBatis, by default, will return `null` + instead of an instantiated object with all its properties set to `null`. + This case expression, for the QG name, is designed to preserve that behavior. + --> + CASE WHEN qgc.operator IS NULL THEN NULL ELSE qg.name END AS qualityGateName, m.short_name as description, qgc.operator as operator, m.val_type as valueType, diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml index 7506b52f060..6281acad179 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/report/RegulatoryReportMapper.xml @@ -69,8 +69,8 @@ left outer join issues_impacts ii on i.kee = ii.issue_key where i.project_uuid=#{branchUuid,jdbcType=VARCHAR} and i.status !='CLOSED' - <!--BUG, VULNERABILITY, SECURITY_HOTSPOT --> - and i.issue_type in (2, 3, 4) + <!--CODE_SMELL, BUG, VULNERABILITY, SECURITY_HOTSPOT --> + and i.issue_type in (1, 2, 3, 4) order by i.kee, ic.issue_change_creation_date </select> </mapper> diff --git a/server/sonar-main/src/main/java/org/sonar/application/es/EsSettings.java b/server/sonar-main/src/main/java/org/sonar/application/es/EsSettings.java index 46f57e2c65c..dcc39aa99a5 100644 --- a/server/sonar-main/src/main/java/org/sonar/application/es/EsSettings.java +++ b/server/sonar-main/src/main/java/org/sonar/application/es/EsSettings.java @@ -252,5 +252,9 @@ public class EsSettings { if (props.value(JAVA_ADDITIONAL_OPS_PROPERTY, "").contains("-D" + ALLOW_MMAP + "=" + Boolean.FALSE)) { builder.put(ALLOW_MMAP, Boolean.FALSE.toString()); } + + if (props.value(JAVA_ADDITIONAL_OPS_PROPERTY, "").contains("-Dcluster.routing.allocation.disk.threshold_enabled=" + Boolean.FALSE)) { + builder.put("cluster.routing.allocation.disk.threshold_enabled", Boolean.FALSE.toString()); + } } } diff --git a/server/sonar-main/src/test/java/org/sonar/application/es/EsSettingsTest.java b/server/sonar-main/src/test/java/org/sonar/application/es/EsSettingsTest.java index 012445ff83c..974ffd79dcb 100644 --- a/server/sonar-main/src/test/java/org/sonar/application/es/EsSettingsTest.java +++ b/server/sonar-main/src/test/java/org/sonar/application/es/EsSettingsTest.java @@ -367,6 +367,25 @@ public class EsSettingsTest { } @Test + @UseDataProvider("clusterEnabledOrNot") + public void disable_disk_threshold_if_configured_in_search_additional_props(boolean clusterEnabled) throws Exception { + Props props = minProps(clusterEnabled); + props.set("sonar.search.javaAdditionalOpts", "-Dcluster.routing.allocation.disk.threshold_enabled=false"); + Map<String, String> settings = new EsSettings(props, new EsInstallation(props), system).build(); + + assertThat(settings).containsEntry("cluster.routing.allocation.disk.threshold_enabled", "false"); + } + + @Test + @UseDataProvider("clusterEnabledOrNot") + public void disk_threshold_not_set_by_default(boolean clusterEnabled) throws Exception { + Props props = minProps(clusterEnabled); + Map<String, String> settings = new EsSettings(props, new EsInstallation(props), system).build(); + + assertThat(settings.get("cluster.routing.allocation.disk.threshold_enabled")).isNull(); + } + + @Test public void configureSecurity_givenClusterSearchPasswordNotProvided_dontAddXpackParameters() throws Exception { Props props = minProps(true); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/feature/SonarQubeFeature.java b/server/sonar-server-common/src/main/java/org/sonar/server/feature/SonarQubeFeature.java index af149a25f55..7a18916216b 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/feature/SonarQubeFeature.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/feature/SonarQubeFeature.java @@ -24,4 +24,12 @@ public interface SonarQubeFeature { String getName(); boolean isAvailable(); + + default boolean isEnabled() { + return isAvailable(); + } + + default void setEnabled(boolean enabled) { + throw new UnsupportedOperationException("This feature does not support enabling/disabling."); + } } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/TaintChecker.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/TaintChecker.java index f40ddf46ccd..0ffc6baebed 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/TaintChecker.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/TaintChecker.java @@ -78,7 +78,7 @@ public class TaintChecker { private List<String> initializeRepositories() { List<String> repositories = new ArrayList<>(List.of("gosecurity", "javasecurity", "jssecurity", "kotlinsecurity", "phpsecurity", "pythonsecurity", - "roslyn.sonaranalyzer.security.cs", "tssecurity")); + "roslyn.sonaranalyzer.security.cs", "tssecurity", "vbnetsecurity")); if (!config.hasKey(EXTRA_TAINT_REPOSITORIES)) { return repositories; diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/metric/StandardToMQRMetrics.java b/server/sonar-server-common/src/main/java/org/sonar/server/metric/StandardToMQRMetrics.java index 53d39f62652..6ebf315f6ca 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/metric/StandardToMQRMetrics.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/metric/StandardToMQRMetrics.java @@ -22,6 +22,7 @@ package org.sonar.server.metric; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import java.util.Optional; +import java.util.Set; import org.sonar.api.measures.CoreMetrics; import org.sonar.core.metric.SoftwareQualitiesMetrics; @@ -120,6 +121,14 @@ public class StandardToMQRMetrics { return MQR_TO_STANDARD_MODE_METRICS.containsKey(metricKey); } + public static Set<String> getMQRMetrics() { + return STANDARD_TO_MQR_MODE_METRICS.keySet(); + } + + public static Set<String> getStandardMetrics() { + return MQR_TO_STANDARD_MODE_METRICS.keySet(); + } + /** * Retrieves equivalent metric in the other mode. Return empty if metric has no equivalence */ diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/TaintCheckerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/TaintCheckerTest.java index 4cbf7aeeb41..3a2471084ec 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/TaintCheckerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/TaintCheckerTest.java @@ -44,7 +44,7 @@ public class TaintCheckerTest { public void test_getTaintIssuesOnly() { List<IssueDto> taintIssues = underTest.getTaintIssuesOnly(getIssues()); - assertThat(taintIssues).hasSize(8); + assertThat(taintIssues).hasSize(9); assertThat(taintIssues.get(0).getKey()).isEqualTo("taintIssue1"); assertThat(taintIssues.get(1).getKey()).isEqualTo("taintIssue2"); assertThat(taintIssues.get(2).getKey()).isEqualTo("taintIssue3"); @@ -53,6 +53,7 @@ public class TaintCheckerTest { assertThat(taintIssues.get(5).getKey()).isEqualTo("taintIssue6"); assertThat(taintIssues.get(6).getKey()).isEqualTo("taintIssue7"); assertThat(taintIssues.get(7).getKey()).isEqualTo("taintIssue8"); + assertThat(taintIssues.get(8).getKey()).isEqualTo("taintIssue9"); } @Test @@ -71,7 +72,7 @@ public class TaintCheckerTest { Map<Boolean, List<IssueDto>> issuesByTaintStatus = underTest.mapIssuesByTaintStatus(getIssues()); assertThat(issuesByTaintStatus.keySet()).hasSize(2); - assertThat(issuesByTaintStatus.get(true)).hasSize(8); + assertThat(issuesByTaintStatus.get(true)).hasSize(9); assertThat(issuesByTaintStatus.get(false)).hasSize(3); assertThat(issuesByTaintStatus.get(true).get(0).getKey()).isEqualTo("taintIssue1"); @@ -91,9 +92,9 @@ public class TaintCheckerTest { @Test public void test_getTaintRepositories() { assertThat(underTest.getTaintRepositories()) - .hasSize(8) + .hasSize(9) .containsExactlyInAnyOrder("gosecurity", "javasecurity", "jssecurity", "kotlinsecurity", "phpsecurity", "pythonsecurity", - "roslyn.sonaranalyzer.security.cs", "tssecurity"); + "roslyn.sonaranalyzer.security.cs", "tssecurity", "vbnetsecurity"); } @Test @@ -102,9 +103,9 @@ public class TaintCheckerTest { when(configuration.getStringArray(EXTRA_TAINT_REPOSITORIES)).thenReturn(new String[]{"extra-1", "extra-2"}); TaintChecker underTest = new TaintChecker(configuration); assertThat(underTest.getTaintRepositories()) - .hasSize(10) + .hasSize(11) .containsExactlyInAnyOrder("gosecurity", "javasecurity", "jssecurity", "kotlinsecurity", "phpsecurity", "pythonsecurity", - "roslyn.sonaranalyzer.security.cs", "tssecurity", "extra-1", "extra-2"); + "roslyn.sonaranalyzer.security.cs", "tssecurity", "vbnetsecurity", "extra-1", "extra-2"); } @Test @@ -141,6 +142,7 @@ public class TaintCheckerTest { issues.add(createIssueWithRepository("taintIssue6", "pythonsecurity")); issues.add(createIssueWithRepository("taintIssue7", "kotlinsecurity")); issues.add(createIssueWithRepository("taintIssue8", "gosecurity")); + issues.add(createIssueWithRepository("taintIssue9", "vbnetsecurity")); issues.add(createIssueWithRepository("standardIssue1", "java")); issues.add(createIssueWithRepository("standardIssue2", "python")); diff --git a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java index d187336783d..f69a9019e4d 100644 --- a/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java +++ b/server/sonar-webserver-common/src/it/java/org/sonar/server/common/user/service/UserServiceIT.java @@ -846,6 +846,52 @@ public class UserServiceIT { assertThat(updatedUser.getExternalLogin()).isEqualTo("prov_login"); } + @Test + public void updateUser_whenUpdatingScmAccountsAndInstanceManaged_shouldChange() { + when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(true); + + UserDto userDto = db.users().insertUser(); + UpdateUser updateUser = new UpdateUser(); + updateUser.setScmAccounts(List.of("newaccount")); + + userService.updateUser(userDto.getUuid(), updateUser); + + UserDto updatedUser = db.users().selectUserByLogin(userDto.getLogin()).orElseThrow(); + + assertThat(updatedUser.getSortedScmAccounts()).isEqualTo(List.of("newaccount")); + } + + @DataProvider + public static Object[][] managedInstanceBlockedFields() { + return new Object[][] { + { "email", (Function<UpdateUser,UpdateUser>) updateUser -> updateUser.setEmail("new@email.com")}, + { "email", (Function<UpdateUser,UpdateUser>) updateUser -> updateUser.setName("new name")}, + { "email", (Function<UpdateUser,UpdateUser>) updateUser -> updateUser.setExternalIdentityProviderLogin("new-external-login")}, + { "email", (Function<UpdateUser,UpdateUser>) updateUser -> updateUser.setExternalIdentityProvider("LDAP")}, + { "email", (Function<UpdateUser,UpdateUser>) updateUser -> updateUser.setExternalIdentityProviderId("new-provider-id")}, + }; + } + + @Test + @UseDataProvider("managedInstanceBlockedFields") + public void updateUser_whenUpdatingBlockedFieldAndInstanceManaged_shouldThrow(String fieldName, + Function<UpdateUser, UpdateUser> updateUserFunction) { + doThrow(BadRequestException.create("User information's cannot be updated when the instance is externally managed")) + .when(managedInstanceChecker).throwIfInstanceIsManaged(any()); + + UserDto userDto = db.users().insertUser(); + + assertThatThrownBy(() -> updateUser(userDto, updateUserFunction)) + .isInstanceOf(BadRequestException.class) + .hasMessage("User information's cannot be updated when the instance is externally managed"); + } + + private void updateUser(UserDto userDto, Function<UpdateUser, UpdateUser> updateUserFunction) { + UpdateUser updateUser = new UpdateUser(); + updateUser = updateUserFunction.apply(updateUser); + userService.updateUser(userDto.getUuid(), updateUser); + } + @DataProvider public static Object[][] updateUserProvider() { return new Object[][] { diff --git a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/user/service/UserService.java b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/user/service/UserService.java index 95f24094f58..23a78e60169 100644 --- a/server/sonar-webserver-common/src/main/java/org/sonar/server/common/user/service/UserService.java +++ b/server/sonar-webserver-common/src/main/java/org/sonar/server/common/user/service/UserService.java @@ -222,7 +222,7 @@ public class UserService { public UserInformation updateUser(String uuid, UpdateUser updateUser) { try (DbSession dbSession = dbClient.openSession(false)) { throwIfInvalidChangeOfExternalProvider(updateUser); - throwIfManagedInstanceAndNameOrEmailUpdated(updateUser); + throwIfManagedInstanceAndNameOrEmailOrExternalInfoUpdated(updateUser); UserDto userDto = findUserOrThrow(uuid, dbSession); userUpdater.updateAndCommit(dbSession, userDto, updateUser, u -> { }); @@ -248,11 +248,15 @@ public class UserService { Optional.ofNullable(updateUser.externalIdentityProvider()).ifPresent(this::assertProviderIsSupported); } - private void throwIfManagedInstanceAndNameOrEmailUpdated(UpdateUser updateUser) { + private void throwIfManagedInstanceAndNameOrEmailOrExternalInfoUpdated(UpdateUser updateUser) { boolean isNameChanged = updateUser.isNameChanged(); boolean isEmailDefined = updateUser.isEmailChanged(); - if (isNameChanged || isEmailDefined) { - managedInstanceChecker.throwIfInstanceIsManaged("User name and email cannot be updated when the instance is externally managed"); + boolean isExternalLoginChanged = updateUser.isExternalIdentityProviderLoginChanged(); + boolean isExternalProviderChanged = updateUser.isExternalIdentityProviderChanged(); + boolean isExternalIdChanged = updateUser.isExternalIdentityProviderIdChanged(); + + if (isNameChanged || isEmailDefined || isExternalLoginChanged || isExternalProviderChanged || isExternalIdChanged) { + managedInstanceChecker.throwIfInstanceIsManaged("User information's cannot be updated when the instance is externally managed"); } } diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 9235bc57b1a..6b2c826f2c9 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -871,7 +871,7 @@ public class IssueIndex { if (newCodeOnReference != null) { filters.addFilter( FIELD_ISSUE_NEW_CODE_REFERENCE, new SimpleFieldFilterScope(FIELD_ISSUE_NEW_CODE_REFERENCE), - termQuery(FIELD_ISSUE_NEW_CODE_REFERENCE, true)); + termQuery(FIELD_ISSUE_NEW_CODE_REFERENCE, newCodeOnReference)); } } diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java index a8c4216b14f..39e1189e5a6 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java @@ -269,18 +269,22 @@ public class IssueQueryFactory { ComponentDto component = componentUuids.iterator().next(); if (!QUALIFIERS_WITHOUT_LEAK_PERIOD.contains(component.qualifier()) && request.getPullRequest() == null) { - Optional<SnapshotDto> snapshot = getLastAnalysis(dbSession, component); - if (!snapshot.isEmpty() && isLastAnalysisFromReAnalyzedReferenceBranch(dbSession, snapshot.get())) { - builder.newCodeOnReference(true); - return; - } - // if last analysis has no period date, then no issue should be considered new. - Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(snapshot); - setCreatedAfterFromDates(builder, createdAfterFromSnapshot, null, false); + setInNewCodePeriod(dbSession, builder, component.uuid()); } } } + private void setInNewCodePeriod(DbSession dbSession, IssueQuery.Builder builder, String componentUuid) { + Optional<SnapshotDto> snapshot = getLastAnalysis(dbSession, componentUuid); + if (!snapshot.isEmpty() && isLastAnalysisFromReAnalyzedReferenceBranch(dbSession, snapshot.get())) { + builder.newCodeOnReference(true); + return; + } + // if last analysis has no period date, then no issue should be considered new. + Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(snapshot); + setCreatedAfterFromDates(builder, createdAfterFromSnapshot, null, false); + } + private static boolean notInNewCodePeriod(SearchRequest request) { Boolean inNewCodePeriod = request.getInNewCodePeriod(); inNewCodePeriod = Boolean.TRUE.equals(inNewCodePeriod); @@ -301,8 +305,8 @@ public class IssueQueryFactory { .isPresent(); } - private Optional<SnapshotDto> getLastAnalysis(DbSession dbSession, ComponentDto component) { - return dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.uuid()); + private Optional<SnapshotDto> getLastAnalysis(DbSession dbSession, String componentUuid) { + return dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, componentUuid); } private List<SnapshotDto> getLastAnalysis(DbSession dbSession, Set<String> projectUuids) { diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/email/config/controller/EmailConfigurationController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/email/config/controller/EmailConfigurationController.java index a62ec04c33a..8fb0f5e05a3 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/email/config/controller/EmailConfigurationController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/email/config/controller/EmailConfigurationController.java @@ -30,7 +30,6 @@ import org.sonar.server.v2.api.email.config.request.EmailConfigurationUpdateRest import org.sonar.server.v2.api.email.config.resource.EmailConfigurationResource; import org.sonar.server.v2.api.email.config.response.EmailConfigurationSearchRestResponse; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -44,6 +43,7 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.EMAIL_CONFIGURATION_ENDPOINT; import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(EMAIL_CONFIGURATION_ENDPOINT) @RestController @@ -58,7 +58,7 @@ public interface EmailConfigurationController { extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) EmailConfigurationResource createEmailConfiguration(@Valid @RequestBody EmailConfigurationCreateRestRequest createRequest); - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch an email configuration", description = """ Fetch a Email configuration. Requires 'Administer System' permission. @@ -76,7 +76,7 @@ public interface EmailConfigurationController { extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) EmailConfigurationSearchRestResponse searchEmailConfigurations(); - @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Update an email configuration", description = """ Update an email configuration. Requires 'Administer System' permission. diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/config/controller/GithubConfigurationController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/config/controller/GithubConfigurationController.java index dda8fdbc4b7..d246cb4af26 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/config/controller/GithubConfigurationController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/github/config/controller/GithubConfigurationController.java @@ -30,7 +30,6 @@ import org.sonar.server.v2.api.github.config.request.GithubConfigurationUpdateRe import org.sonar.server.v2.api.github.config.resource.GithubConfigurationResource; import org.sonar.server.v2.api.github.config.response.GithubConfigurationSearchRestResponse; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -44,12 +43,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.GITHUB_CONFIGURATION_ENDPOINT; import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(GITHUB_CONFIGURATION_ENDPOINT) @RestController public interface GithubConfigurationController { - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch a GitHub configuration", description = """ Fetch a GitHub configuration. Requires 'Administer System' permission. @@ -67,7 +67,7 @@ public interface GithubConfigurationController { extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) GithubConfigurationSearchRestResponse searchGithubConfiguration(); - @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Update a GitHub configuration", description = """ Update a GitHub configuration. Requires 'Administer System' permission. diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java index a00f7cd0891..b3ebde2230f 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/gitlab/config/controller/GitlabConfigurationController.java @@ -30,7 +30,6 @@ import org.sonar.server.v2.api.gitlab.config.request.GitlabConfigurationUpdateRe import org.sonar.server.v2.api.gitlab.config.resource.GitlabConfigurationResource; import org.sonar.server.v2.api.gitlab.config.response.GitlabConfigurationSearchRestResponse; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -44,12 +43,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.GITLAB_CONFIGURATION_ENDPOINT; import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(GITLAB_CONFIGURATION_ENDPOINT) @RestController public interface GitlabConfigurationController { - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch a GitLab configuration", description = """ Fetch a GitLab configuration. Requires 'Administer System' permission. @@ -67,7 +67,7 @@ public interface GitlabConfigurationController { extensions = @Extension(properties = {@ExtensionProperty(name = INTERNAL, value = "true")})) GitlabConfigurationSearchRestResponse searchGitlabConfiguration(); - @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Update a Gitlab configuration", description = """ Update a Gitlab configuration. Requires 'Administer System' permission. diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java index f6f6a149679..66bda515c44 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/group/controller/GroupController.java @@ -35,7 +35,6 @@ import org.sonar.server.v2.api.group.response.GroupsSearchRestResponse; import org.sonar.server.v2.api.model.RestPage; import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -49,12 +48,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.GROUPS_ENDPOINT; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(GROUPS_ENDPOINT) @RestController public interface GroupController { - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Group search", description = """ Get the list of groups. @@ -66,12 +66,12 @@ public interface GroupController { extensions = @Extension(properties = {@ExtensionProperty(name = "internal", value = "true")}), hidden = true) String excludedUserId, @Valid @ParameterObject RestPage restPage); - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch a single group", description = "Fetch a single group.") GroupRestResponse fetchGroup(@PathVariable("id") @Parameter(description = "The id of the group to fetch.", required = true, in = ParameterIn.PATH) String id); - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.CREATED) @Operation(summary = "Create a new group", description = "Create a new group.") GroupRestResponse create(@Valid @RequestBody GroupCreateRestRequest request); @@ -81,7 +81,7 @@ public interface GroupController { @Operation(summary = "Deletes a group", description = "Deletes a group.") void deleteGroup(@PathVariable("id") @Parameter(description = "The ID of the group to delete.", required = true, in = ParameterIn.PATH) String id); - @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Update a group", description = """ Update a group name or description. diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/mode/controller/ModeController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/mode/controller/ModeController.java index 336584a778a..3dec8655db4 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/mode/controller/ModeController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/mode/controller/ModeController.java @@ -34,12 +34,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; import static org.sonar.server.v2.WebApiEndpoints.MODE_ENDPOINT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(MODE_ENDPOINT) @RestController public interface ModeController { - @GetMapping(path = "") + @GetMapping(path = "", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Retrieve current instance Mode", description = """ Fetch the current instance mode. Can be Multi-Quality Rules (MQR) Mode or Standard Experience. diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/projectbindings/controller/ProjectBindingsController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/projectbindings/controller/ProjectBindingsController.java index 64d3eda84b0..8a7ca41d895 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/projectbindings/controller/ProjectBindingsController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/projectbindings/controller/ProjectBindingsController.java @@ -37,12 +37,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.INTERNAL; import static org.sonar.server.v2.WebApiEndpoints.PROJECT_BINDINGS_ENDPOINT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(PROJECT_BINDINGS_ENDPOINT) @RestController public interface ProjectBindingsController { - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @Operation( operationId = "getProjectBinding", summary = "Fetch a single Project Binding", diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java index 52563f6d997..1e478f0b602 100644 --- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java +++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/api/user/controller/UserController.java @@ -35,7 +35,6 @@ import org.sonar.server.v2.api.user.response.UserRestResponse; import org.sonar.server.v2.api.user.response.UsersSearchRestResponse; import org.springdoc.core.annotations.ParameterObject; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -49,12 +48,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.sonar.server.v2.WebApiEndpoints.JSON_MERGE_PATCH_CONTENT_TYPE; import static org.sonar.server.v2.WebApiEndpoints.USER_ENDPOINT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @RequestMapping(USER_ENDPOINT) @RestController public interface UserController { - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Users search", description = """ Get a list of users. By default, only active users are returned. @@ -82,7 +82,7 @@ public interface UserController { @PathVariable("id") @Parameter(description = "The ID of the user to delete.", required = true, in = ParameterIn.PATH) String id, @RequestParam(value = "anonymize", required = false, defaultValue = "false") @Parameter(description = "Anonymize user in addition to deactivating it.") Boolean anonymize); - @GetMapping(path = "/{id}") + @GetMapping(path = "/{id}", produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Fetch a single user", description = """ Fetch a single user. @@ -98,14 +98,14 @@ public interface UserController { """) UserRestResponse fetchUser(@PathVariable("id") @Parameter(description = "The id of the user to fetch.", required = true, in = ParameterIn.PATH) String id); - @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = MediaType.APPLICATION_JSON_VALUE) + @PatchMapping(path = "/{id}", consumes = JSON_MERGE_PATCH_CONTENT_TYPE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "Update a user", description = """ Update users attributes. """) UserRestResponse updateUser(@PathVariable("id") String id, @Valid @RequestBody UserUpdateRestRequest updateRequest); - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @PostMapping(consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) @Operation(summary = "User creation", description = """ Create a user. diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/feature/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/feature/ws/ListAction.java index 0d4219e0805..a7db09fc823 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/feature/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/feature/ws/ListAction.java @@ -51,7 +51,7 @@ public class ListAction implements WsAction { try (JsonWriter json = response.newJsonWriter()) { json.beginArray(); sonarQubeFeatures.stream() - .filter(SonarQubeFeature::isAvailable) + .filter(SonarQubeFeature::isEnabled) .forEach(f -> json.value(f.getName())); json.endArray(); } diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CspFilter.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CspFilter.java index 7015b1a0b46..195aa01c6bf 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CspFilter.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/web/CspFilter.java @@ -35,8 +35,6 @@ import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletResponse; public class CspFilter implements Filter { - private static final String BEAMER_SRC = " https://*.getbeamer.com "; - private final List<String> cspHeaders = new ArrayList<>(); private String policies = null; @@ -48,13 +46,13 @@ public class CspFilter implements Filter { cspPolicies.add("default-src 'self'"); cspPolicies.add("base-uri 'none'"); cspPolicies.add("connect-src 'self' http: https:"); - cspPolicies.add("font-src 'self' data:" + BEAMER_SRC); - cspPolicies.add("frame-src" + BEAMER_SRC); + cspPolicies.add("font-src 'self' data:"); + cspPolicies.add("frame-src"); cspPolicies.add("img-src * data: blob:"); cspPolicies.add("object-src 'none'"); // the hash below corresponds to the window.__assetsPath script in index.html - cspPolicies.add("script-src 'self'" + BEAMER_SRC + getAssetsPathScriptCSPHash(filterConfig.getServletContext().getContextPath())); - cspPolicies.add("style-src 'self' 'unsafe-inline'" + BEAMER_SRC); + cspPolicies.add("script-src 'self' " + getAssetsPathScriptCSPHash(filterConfig.getServletContext().getContextPath())); + cspPolicies.add("style-src 'self' 'unsafe-inline'"); cspPolicies.add("worker-src 'self'"); this.policies = String.join("; ", cspPolicies).trim(); } diff --git a/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CspFilterTest.java b/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CspFilterTest.java index b2ef0146d4e..c4e0b3cfcd4 100644 --- a/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CspFilterTest.java +++ b/server/sonar-webserver/src/test/java/org/sonar/server/platform/web/CspFilterTest.java @@ -41,12 +41,12 @@ public class CspFilterTest { private static final String EXPECTED = "default-src 'self'; " + "base-uri 'none'; " + "connect-src 'self' http: https:; " + - "font-src 'self' data: https://*.getbeamer.com ; " + - "frame-src https://*.getbeamer.com ; " + + "font-src 'self' data:; " + + "frame-src; " + "img-src * data: blob:; " + "object-src 'none'; " + - "script-src 'self' https://*.getbeamer.com 'sha256-hK8SVWFNHY0UhP61DBzX/3fvT74EI8u6/jRQvUKeZoU='; " + - "style-src 'self' 'unsafe-inline' https://*.getbeamer.com ; " + + "script-src 'self' 'sha256-hK8SVWFNHY0UhP61DBzX/3fvT74EI8u6/jRQvUKeZoU='; " + + "style-src 'self' 'unsafe-inline'; " + "worker-src 'self'"; private final ServletContext servletContext = mock(ServletContext.class, RETURNS_MOCKS); private final HttpServletResponse response = mock(HttpServletResponse.class); @@ -75,7 +75,7 @@ public class CspFilterTest { doInit(); HttpServletRequest request = newRequest("/"); underTest.doFilter(request, response, chain); - verify(response).setHeader(eq("Content-Security-Policy"), contains("script-src 'self' https://*.getbeamer.com 'sha256-D1jaqcDDM2TM2STrzE42NNqyKR9PlptcHDe6tyaBcuM='; ")); + verify(response).setHeader(eq("Content-Security-Policy"), contains("script-src 'self' 'sha256-D1jaqcDDM2TM2STrzE42NNqyKR9PlptcHDe6tyaBcuM='; ")); verify(chain).doFilter(request, response); } |