diff options
author | Dejan Milisavljevic <dejan.milisavljevic@sonarsource.com> | 2024-12-11 15:25:51 +0100 |
---|---|---|
committer | Steve Marion <steve.marion@sonarsource.com> | 2024-12-18 11:13:23 +0100 |
commit | 742bdb16f309b8f7573d07af279e9aed8311aed4 (patch) | |
tree | acb740856386602ac70c12cbcd64cdd5a96b1aeb /server | |
parent | 01db3ec4c38768361506abc43dac0d379314276b (diff) | |
download | sonarqube-742bdb16f309b8f7573d07af279e9aed8311aed4.tar.gz sonarqube-742bdb16f309b8f7573d07af279e9aed8311aed4.zip |
SONAR-23688 Add facet and filter on active_impactSeverities
Co-authored-by: OrlovAlexander <alexander.orlov@sonarsource.com>
Diffstat (limited to 'server')
11 files changed, 254 insertions, 52 deletions
diff --git a/server/sonar-server-common/src/it/java/org/sonar/server/rule/index/RuleIndexIT.java b/server/sonar-server-common/src/it/java/org/sonar/server/rule/index/RuleIndexIT.java index 17865560586..17ab8191225 100644 --- a/server/sonar-server-common/src/it/java/org/sonar/server/rule/index/RuleIndexIT.java +++ b/server/sonar-server-common/src/it/java/org/sonar/server/rule/index/RuleIndexIT.java @@ -66,9 +66,12 @@ import static org.assertj.core.api.Assertions.entry; import static org.junit.Assert.fail; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.sonar.api.issue.impact.Severity.HIGH; +import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY; +import static org.sonar.api.issue.impact.SoftwareQuality.RELIABILITY; +import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY; import static org.sonar.api.rule.Severity.BLOCKER; import static org.sonar.api.rule.Severity.CRITICAL; -import static org.sonar.api.rule.Severity.INFO; import static org.sonar.api.rule.Severity.MAJOR; import static org.sonar.api.rule.Severity.MINOR; import static org.sonar.api.rules.RuleType.BUG; @@ -468,10 +471,10 @@ class RuleIndexIT { void search_by_security_cwe_return_correct_data_based_on_mode(boolean mqrMode) { doReturn(Optional.of(mqrMode)).when(config).getBoolean(MULTI_QUALITY_MODE_ENABLED); RuleDto rule1 = createRule(setSecurityStandards(of("cwe:543", "cwe:123", "owaspTop10:a1")), - r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); RuleDto rule2 = createRule(setSecurityStandards(of("cwe:543", "owaspTop10:a1")), r -> r.setType(SECURITY_HOTSPOT)); createRule(setSecurityStandards(of("owaspTop10:a1")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); index(); RuleQuery query = new RuleQuery().setCwe(of("543")); @@ -484,10 +487,10 @@ class RuleIndexIT { void search_by_security_owaspTop10_2017_return_correct_data_based_on_mode(boolean mqrMode) { doReturn(Optional.of(mqrMode)).when(config).getBoolean(MULTI_QUALITY_MODE_ENABLED); RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:543")), - r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); RuleDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:543")), r -> r.setType(SECURITY_HOTSPOT)); createRule(setSecurityStandards(of("cwe:543")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); index(); RuleQuery query = new RuleQuery().setOwaspTop10(of("a5", "a10")); @@ -500,10 +503,10 @@ class RuleIndexIT { void search_by_security_owaspTop10_2021_return_correct_data_based_on_mode(boolean mqrMode) { doReturn(Optional.of(mqrMode)).when(config).getBoolean(MULTI_QUALITY_MODE_ENABLED); RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10-2021:a1", "owaspTop10-2021:a10", "cwe:543")), - r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); RuleDto rule2 = createRule(setSecurityStandards(of("owaspTop10-2021:a10", "cwe:543")), r -> r.setType(SECURITY_HOTSPOT)); createRule(setSecurityStandards(of("cwe:543")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); index(); RuleQuery query = new RuleQuery().setOwaspTop10For2021(of("a5", "a10")); @@ -516,10 +519,10 @@ class RuleIndexIT { void search_by_security_sansTop25_return_correct_data_based_on_mode(boolean mqrMode) { doReturn(Optional.of(mqrMode)).when(config).getBoolean(MULTI_QUALITY_MODE_ENABLED); RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10:a10", "cwe:89")), - r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); RuleDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")), r -> r.setType(SECURITY_HOTSPOT)); createRule(setSecurityStandards(of("cwe:306")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); index(); RuleQuery query = new RuleQuery().setSansTop25(of(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)); @@ -532,9 +535,9 @@ class RuleIndexIT { void search_by_security_sonarsource_return_correct_data_based_on_mode(boolean mqrMode) { doReturn(Optional.of(mqrMode)).when(config).getBoolean(MULTI_QUALITY_MODE_ENABLED); RuleDto rule1 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10-2021:a10", "cwe:89")), - r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(VULNERABILITY).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); createRule(setSecurityStandards(of("owaspTop10:a10", "cwe:829")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); RuleDto rule3 = createRule(setSecurityStandards(of("cwe:601")), r -> r.setType(SECURITY_HOTSPOT)); index(); @@ -551,7 +554,7 @@ class RuleIndexIT { //Should not be counted in Standard mode because it is not a Vulnerability type RuleDto rule2 = createRule(setSecurityStandards(of("owaspTop10:a1", "owaspTop10-2021:a10", "cwe:89")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.SECURITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SECURITY, Severity.HIGH)))); //Hotspots should be counted in both modes RuleDto rule3 = createRule(setSecurityStandards(of("cwe:601")), r -> r.setType(SECURITY_HOTSPOT)); @@ -582,7 +585,7 @@ class RuleIndexIT { // Should be ignore because it is not a hotspot, and not a vulnerability (in Standard mode) and not having Security impact (in MQR mode) createRule(setSecurityStandards(of("cwe:787")), - r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)))); + r -> r.setType(CODE_SMELL).replaceAllDefaultImpacts(List.of(new ImpactDto(MAINTAINABILITY, Severity.HIGH)))); index(); RuleQuery query = new RuleQuery(); @@ -633,10 +636,10 @@ class RuleIndexIT { @Test void search_by_any_of_severities() { createRule(setSeverity(BLOCKER)); - RuleDto info = createRule(setSeverity(INFO)); + RuleDto info = createRule(setSeverity(org.sonar.api.rule.Severity.INFO)); index(); - RuleQuery query = new RuleQuery().setSeverities(asList(INFO, MINOR)); + RuleQuery query = new RuleQuery().setSeverities(asList(org.sonar.api.rule.Severity.INFO, MINOR)); SearchIdResult<String> results = underTest.search(query, new SearchOptions()); assertThat(results.getUuids()).containsOnly(info.getUuid()); @@ -774,7 +777,7 @@ class RuleIndexIT { void search_by_activation_and_severity() { RuleDto major = createRule(setSeverity(MAJOR)); RuleDto minor = createRule(setSeverity(MINOR)); - createRule(setSeverity(INFO)); + createRule(setSeverity(org.sonar.api.rule.Severity.INFO)); QProfileDto profile1 = createJavaProfile(); QProfileDto profile2 = createJavaProfile(); db.qualityProfiles().activateRule(profile1, major, ar -> ar.setSeverity(BLOCKER)); @@ -804,6 +807,100 @@ class RuleIndexIT { verifyNoFacet(query, RuleIndex.FACET_ACTIVE_SEVERITIES); } + @Test + void search_by_activation_returns_impact_severity_facet() { + RuleDto rule1 = createRule(); + RuleDto rule2 = createRule(setSeverity(MINOR)); + RuleDto rule3 = createRule(); + RuleDto rule4 = createRule(); + QProfileDto profile1 = createJavaProfile(); + QProfileDto profile2 = createJavaProfile(); + db.qualityProfiles().activateRule(profile1, rule1, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.INFO))); + db.qualityProfiles().activateRule(profile1, rule2, ar -> ar.setImpacts(Map.of(SECURITY, Severity.LOW, MAINTAINABILITY, Severity.INFO, + RELIABILITY, HIGH))); + db.qualityProfiles().activateRule(profile1, rule3, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.BLOCKER, RELIABILITY, Severity.BLOCKER))); + db.qualityProfiles().activateRule(profile1, rule4, ar -> ar.setImpacts(Map.of(SECURITY, Severity.MEDIUM, RELIABILITY, + Severity.MEDIUM))); + + // Ignored because on profile2 which is not part of the query + db.qualityProfiles().activateRule(profile2, rule1, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.INFO))); + index(); + + RuleQuery query = newRuleQuery().setActivation(true).setQProfile(profile1); + + SearchIdResult result = underTest.search(query, + new SearchOptions().addFacets(singletonList("active_impactSeverities"))); + + assertThat(result.getFacets().getAll()).hasSize(1); + assertThat(result.getFacets().getAll().get("active_impactSeverities")) + .containsOnly( + entry("BLOCKER", 2L), + entry("HIGH", 1L), + entry("MEDIUM", 1L), + entry("LOW", 1L), + entry("INFO", 2L) + ); + } + + @Test + void search_by_activation_and_impact_severity_returns_impact_severity_facet() { + RuleDto rule1 = createRule(setImpacts(List.of(new ImpactDto(SECURITY, Severity.MEDIUM)))); + RuleDto rule2 = createRule(setImpacts(List.of(new ImpactDto(SECURITY, Severity.BLOCKER)))); + RuleDto rule3 = createRule(); + RuleDto rule4 = createRule(); + QProfileDto profile1 = createJavaProfile(); + QProfileDto profile2 = createJavaProfile(); + db.qualityProfiles().activateRule(profile1, rule1, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.INFO)).setSeverity("INFO")); + db.qualityProfiles().activateRule(profile1, rule2, ar -> ar.setImpacts(Map.of(SECURITY, Severity.LOW, MAINTAINABILITY, Severity.INFO, + RELIABILITY, HIGH)).setSeverity("INFO")); + db.qualityProfiles().activateRule(profile1, rule3, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.BLOCKER, RELIABILITY, Severity.BLOCKER)).setSeverity("MAJOR")); + db.qualityProfiles().activateRule(profile1, rule4, ar -> ar.setImpacts(Map.of(SECURITY, Severity.MEDIUM, RELIABILITY, + Severity.MEDIUM)).setSeverity("MAJOR")); + + // Should be ignored because it is on profile2 which is not part of the query + db.qualityProfiles().activateRule(profile2, rule1, ar -> ar.setImpacts(Map.of(SECURITY, Severity.BLOCKER, MAINTAINABILITY, + Severity.INFO))); + index(); + + RuleQuery query = + newRuleQuery().setActivation(true).setQProfile(profile1).setActiveImpactSeverities(List.of("BLOCKER")); + + SearchIdResult result1 = underTest.search(query, new SearchOptions().addFacets(singletonList("active_impactSeverities"))); + + // Filtering on active Impact Severity should have no effect on the Active Severity Facets + assertThat(result1.getFacets().getAll()).hasSize(1); + assertThat(result1.getFacets().getAll().get("active_impactSeverities")) + .containsOnly( + entry("BLOCKER", 2L), + entry("HIGH", 1L), + entry("MEDIUM", 1L), + entry("LOW", 1L), + entry("INFO", 2L) + ); + assertThat(result1.getUuids()).containsExactlyInAnyOrder(rule1.getUuid(), rule3.getUuid()); + + query = query.setActiveSeverities(List.of("MAJOR")); + + SearchIdResult result2 = underTest.search(query, new SearchOptions().addFacets(singletonList("active_impactSeverities"))); + + // Filters other than "active impact severity" should affect the counts + assertThat(result2.getFacets().getAll()).hasSize(1); + assertThat(result2.getFacets().getAll().get("active_impactSeverities")) + .containsOnly( + entry("BLOCKER", 1L), + entry("HIGH", 0L), + entry("MEDIUM", 1L), + entry("LOW", 0L), + entry("INFO", 0L) + ); + assertThat(result2.getUuids()).containsExactlyInAnyOrder(rule3.getUuid()); + } + private void verifyFacet(RuleQuery query, String facet, Map.Entry<String, Long>... expectedBuckets) { SearchIdResult<String> result = underTest.search(query, new SearchOptions().addFacets(facet)); assertThat(result.getFacets().get(facet)) @@ -870,24 +967,24 @@ class RuleIndexIT { @Test void search_by_software_quality() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); RuleDto phpRule = createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); index(); RuleQuery query = new RuleQuery(); - SearchIdResult result1 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())), + SearchIdResult result1 = underTest.search(query.setImpactSoftwareQualities(List.of(MAINTAINABILITY.name())), new SearchOptions()); assertThat(result1.getUuids()).isEmpty(); query = new RuleQuery(); - SearchIdResult result2 = underTest.search(query.setImpactSoftwareQualities(List.of(SoftwareQuality.SECURITY.name())), + SearchIdResult result2 = underTest.search(query.setImpactSoftwareQualities(List.of(SECURITY.name())), new SearchOptions()); assertThat(result2.getUuids()).containsOnly(phpRule.getUuid()); } @Test void search_by_severity() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.BLOCKER); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.BLOCKER); RuleDto phpRule = createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); index(); @@ -934,8 +1031,8 @@ class RuleIndexIT { @Test void search_should_support_software_quality_facet() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2))); index(); @@ -954,8 +1051,8 @@ class RuleIndexIT { @Test void search_should_support_software_quality_facet_with_filtering() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2))); index(); @@ -975,11 +1072,11 @@ class RuleIndexIT { @Test void search_whenFilteringOnSeverityAndSoftwareQuality_shouldReturnFacet() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.LOW); ImpactDto impactDto4 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.BLOCKER); - ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.BLOCKER); + ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.BLOCKER); ImpactDto impactDto6 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.INFO); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2))); @@ -992,7 +1089,7 @@ class RuleIndexIT { RuleQuery query = new RuleQuery(); SearchIdResult result = underTest.search( - query.setImpactSeverities(of(Severity.LOW.name())).setImpactSoftwareQualities(List.of(SoftwareQuality.MAINTAINABILITY.name())), + query.setImpactSeverities(of(Severity.LOW.name())).setImpactSoftwareQualities(List.of(MAINTAINABILITY.name())), new SearchOptions().addFacets(List.of("impactSoftwareQualities", "impactSeverities"))); assertThat(result.getFacets().getAll()).hasSize(2); @@ -1013,8 +1110,8 @@ class RuleIndexIT { @Test void search_should_support_severity_facet() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.RELIABILITY).setSeverity(Severity.BLOCKER); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2, impactDto3))); @@ -1036,11 +1133,11 @@ class RuleIndexIT { @Test void search_should_support_severity_facet_with_filters() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); - ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.INFO); - ImpactDto impactDto4 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.INFO); - ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.BLOCKER); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.INFO); + ImpactDto impactDto4 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.INFO); + ImpactDto impactDto5 = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.BLOCKER); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2, impactDto3))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto4, impactDto5))); @@ -1063,16 +1160,16 @@ class RuleIndexIT { @Test void search_should_support_software_quality_and_severity_facets_with_filtering() { - ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SoftwareQuality.SECURITY).setSeverity(Severity.HIGH); - ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.LOW); - ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY).setSeverity(Severity.BLOCKER); + ImpactDto impactDto = new ImpactDto().setSoftwareQuality(SECURITY).setSeverity(Severity.HIGH); + ImpactDto impactDto2 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.LOW); + ImpactDto impactDto3 = new ImpactDto().setSoftwareQuality(MAINTAINABILITY).setSeverity(Severity.BLOCKER); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto2))); createRule(setRepositoryKey("php"), setImpacts(List.of(impactDto3))); index(); RuleQuery query = new RuleQuery().setImpactSeverities(of("LOW")) - .setImpactSoftwareQualities(of(SoftwareQuality.MAINTAINABILITY.name())); + .setImpactSoftwareQualities(of(MAINTAINABILITY.name())); SearchOptions searchOptions = new SearchOptions().addFacets(List.of("impactSeverities", "impactSoftwareQualities")); SearchIdResult result2 = underTest.search(query, searchOptions); @@ -1085,8 +1182,8 @@ class RuleIndexIT { entry("INFO", 0L), entry("BLOCKER", 1L)); assertThat(result2.getFacets().getAll().get("impactSoftwareQualities")).containsOnly( - entry(SoftwareQuality.SECURITY.name(), 0L), - entry(SoftwareQuality.MAINTAINABILITY.name(), 1L), + entry(SECURITY.name(), 0L), + entry(MAINTAINABILITY.name(), 1L), entry(SoftwareQuality.RELIABILITY.name(), 0L)); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java index 872fe7a69a9..29cea09e555 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndex.java @@ -96,6 +96,8 @@ import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SEARCH_GR import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SEARCH_WORDS_ANALYZER; import static org.sonar.server.es.newindex.DefaultIndexSettingsElement.SORTABLE_ANALYZER; import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_IMPACTS; +import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_IMPACTS; +import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_IMPACT_SEVERITY; import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_INHERITANCE; import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_PROFILE_UUID; import static org.sonar.server.rule.index.RuleIndexDefinition.FIELD_ACTIVE_RULE_SEVERITY; @@ -157,6 +159,7 @@ public class RuleIndex { public static final String FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY = "cleanCodeAttributeCategories"; public static final String FACET_IMPACT_SOFTWARE_QUALITY = "impactSoftwareQualities"; public static final String FACET_IMPACT_SEVERITY = "impactSeverities"; + public static final String FACET_ACTIVE_IMPACT_SEVERITY = "active_impactSeverities"; private static final BoolQueryBuilder SECURITY_IMPACT_AND_HOTSPOT_FILTER = boolQuery() @@ -461,6 +464,7 @@ public class RuleIndex { addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance()); addTermFilter(activeRuleFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities()); addTermFilter(activeRuleFilter, FIELD_PRIORITIZED_RULE, query.getPrioritizedRule()); + addActiveImpactSeverityFilter(activeRuleFilter, query.getActiveImpactSeverities()); // ChildQuery QueryBuilder childQuery; @@ -472,6 +476,18 @@ public class RuleIndex { return childQuery; } + private static BoolQueryBuilder addActiveImpactSeverityFilter(BoolQueryBuilder filter, @Nullable Collection<String> values) { + if (isNotEmpty(values)) { + BoolQueryBuilder valuesFilter = boolQuery(); + valuesFilter.must(nestedQuery(FIELD_ACTIVE_RULE_IMPACTS, + termsQuery(FIELD_ACTIVE_RULE_IMPACT_SEVERITY, values), + ScoreMode.Avg)); + + filter.must(valuesFilter); + } + return filter; + } + private static BoolQueryBuilder addTermFilter(BoolQueryBuilder filter, String field, @Nullable Collection<String> values) { if (isNotEmpty(values)) { BoolQueryBuilder valuesFilter = boolQuery(); @@ -551,6 +567,7 @@ public class RuleIndex { addImpactSoftwareQualityFacetIfNeeded(options, query, aggregations, stickyFacetBuilder); addImpactSeverityFacetIfNeeded(options, query, aggregations, stickyFacetBuilder); + addActiveRuleImpactSeverityFacetIfNeeded(options, query, aggregations, stickyFacetBuilder); addDefaultSecurityFacets(query, options, aggregations, stickyFacetBuilder); } @@ -594,10 +611,7 @@ public class RuleIndex { Function<String, BoolQueryBuilder> mainQuery = severity -> boolQuery() .filter(QueryBuilders.termQuery(FIELD_RULE_IMPACT_SEVERITY, severity)); - FiltersAggregator.KeyedFilter[] keyedFilters = Arrays.stream(org.sonar.api.issue.impact.Severity.values()) - .map(severity -> new FiltersAggregator.KeyedFilter(severity.name(), - buildSeverityFacetFilter(query, mainQuery, severity.name()))) - .toArray(FiltersAggregator.KeyedFilter[]::new); + FiltersAggregator.KeyedFilter[] keyedFilters = getKeyedFilters(query, mainQuery); NestedAggregationBuilder nestedAggregationBuilder = AggregationBuilders.nested("nested_" + FACET_IMPACT_SEVERITY, FIELD_RULE_IMPACTS) .subAggregation(filters(FACET_IMPACT_SEVERITY, keyedFilters).subAggregation(reverseNested("reverse_nested_" + FIELD_RULE_IMPACT_SEVERITY))); @@ -608,6 +622,57 @@ public class RuleIndex { aggregations.put(FACET_IMPACT_SEVERITY, aggregationBuilder); } + private static void addActiveRuleImpactSeverityFacetIfNeeded(SearchOptions options, RuleQuery query, + Map<String, AggregationBuilder> aggregations, StickyFacetBuilder stickyFacetBuilder) { + QProfileDto profile = query.getQProfile(); + if (!options.getFacets().contains(FACET_ACTIVE_IMPACT_SEVERITY) || profile == null) { + return; + } + + // We are building a children aggregation on active rules + // so the rule filter has to be used as parent filter for active rules + // from which we remove filters that concern active rules ("activation") + HasParentQueryBuilder ruleFilter = JoinQueryBuilders.hasParentQuery( + TYPE_RULE.getType(), + stickyFacetBuilder.getStickyFacetFilter("activation"), + false); + + // Rebuilding the active rule filter without impact severities + BoolQueryBuilder childrenFilter = boolQuery(); + addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid()); + addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_SEVERITY, query.getActiveSeverities()); + RuleIndex.addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance()); + QueryBuilder activeRuleFilter = childrenFilter.must(ruleFilter); + + Function<String, BoolQueryBuilder> mainQuery = severity -> boolQuery() + .filter(QueryBuilders.termQuery(FIELD_ACTIVE_RULE_IMPACT_SEVERITY, severity)); + + FiltersAggregator.KeyedFilter[] keyedFilters = getKeyedFilters(query, mainQuery); + + NestedAggregationBuilder nestedAggregationBuilder = AggregationBuilders.nested("nested_" + FACET_ACTIVE_IMPACT_SEVERITY, + FIELD_ACTIVE_RULE_IMPACTS) + .subAggregation(filters(FACET_ACTIVE_IMPACT_SEVERITY, keyedFilters) + .subAggregation(reverseNested("reverse_nested_" + FIELD_ACTIVE_RULE_IMPACT_SEVERITY)) + ); + + AggregationBuilder activeSeverities = JoinAggregationBuilders.children(FACET_ACTIVE_IMPACT_SEVERITY + "_children", + TYPE_ACTIVE_RULE.getName()) + .subAggregation( + AggregationBuilders.filter(FACET_ACTIVE_IMPACT_SEVERITY + "_filter", activeRuleFilter) + .subAggregation(nestedAggregationBuilder) + ); + + aggregations.put(FACET_ACTIVE_IMPACT_SEVERITY, + AggregationBuilders.global(FACET_ACTIVE_IMPACT_SEVERITY).subAggregation(activeSeverities)); + } + + private static FiltersAggregator.KeyedFilter[] getKeyedFilters(RuleQuery query, Function<String, BoolQueryBuilder> mainQuery) { + return Arrays.stream(org.sonar.api.issue.impact.Severity.values()) + .map(severity -> new FiltersAggregator.KeyedFilter(severity.name(), + buildSeverityFacetFilter(query, mainQuery, severity.name()))) + .toArray(FiltersAggregator.KeyedFilter[]::new); + } + private static BoolQueryBuilder buildSeverityFacetFilter(RuleQuery query, Function<String, BoolQueryBuilder> mainQuery, String value) { BoolQueryBuilder boolQueryBuilder = mainQuery.apply(value); if (isNotEmpty(query.getImpactSoftwareQualities())) { @@ -698,6 +763,7 @@ public class RuleIndex { // Rebuilding the active rule filter without severities BoolQueryBuilder childrenFilter = boolQuery(); addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_PROFILE_UUID, profile.getRulesProfileUuid()); + addActiveImpactSeverityFilter(childrenFilter, query.getActiveImpactSeverities()); RuleIndex.addTermFilter(childrenFilter, FIELD_ACTIVE_RULE_INHERITANCE, query.getInheritance()); QueryBuilder activeRuleFilter = childrenFilter.must(ruleFilter); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java index 7304e98016e..63c637948c3 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleIndexDefinition.java @@ -81,7 +81,6 @@ public class RuleIndexDefinition implements IndexDefinition { public static final String FIELD_ACTIVE_RULE_SEVERITY = "activeRule_severity"; public static final String FIELD_PRIORITIZED_RULE = "activeRule_prioritizedRule"; public static final String FIELD_ACTIVE_RULE_IMPACTS = "activeRule_impacts"; - public static final String FIELD_ACTIVE_RULE_IMPACT_SOFTWARE_QUALITY = FIELD_ACTIVE_RULE_IMPACTS + "." + SUB_FIELD_SOFTWARE_QUALITY; public static final String FIELD_ACTIVE_RULE_IMPACT_SEVERITY = FIELD_ACTIVE_RULE_IMPACTS + "." + SUB_FIELD_SEVERITY; public static final Set<String> SORT_FIELDS = Set.of( diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleQuery.java b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleQuery.java index 7c46f846f6b..a1c7f178a29 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleQuery.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/rule/index/RuleQuery.java @@ -60,6 +60,7 @@ public class RuleQuery { private Collection<String> sonarsourceSecurity; private Collection<String> impactSeverities; private Collection<String> impactSoftwareQualities; + private Collection<String> activeImpactSeverities; private Collection<String> cleanCodeAttributesCategories; private Boolean prioritizedRule; @@ -205,6 +206,16 @@ public class RuleQuery { } @CheckForNull + public Collection<String> getActiveImpactSeverities() { + return activeImpactSeverities; + } + + public RuleQuery setActiveImpactSeverities(@Nullable Collection<String> activeImpactSeverities) { + this.activeImpactSeverities = activeImpactSeverities; + return this; + } + + @CheckForNull public Boolean isTemplate() { return isTemplate; } diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionIT.java index 900de2cf852..4cbf8dd889d 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/ActivateRulesActionIT.java @@ -97,7 +97,8 @@ class ActivateRulesActionIT { "sonarsourceSecurity", "cleanCodeAttributeCategories", "impactSoftwareQualities", - "impactSeverities"); + "impactSeverities", + "active_impactSeverities"); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionIT.java index 9f863094cae..bf8ed8454e0 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualityprofile/ws/DeactivateRulesActionIT.java @@ -94,7 +94,8 @@ public class DeactivateRulesActionIT { "sonarsourceSecurity", "cleanCodeAttributeCategories", "impactSoftwareQualities", - "impactSeverities"); + "impactSeverities", + "active_impactSeverities"); } @Test diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java index b62ea7e17b7..216f77cfcf8 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/rule/ws/SearchActionIT.java @@ -159,7 +159,7 @@ class SearchActionIT { assertThat(def.since()).isEqualTo("4.4"); assertThat(def.isInternal()).isFalse(); assertThat(def.responseExampleAsString()).isNotEmpty(); - assertThat(def.params()).hasSize(32); + assertThat(def.params()).hasSize(33); WebService.Param compareToProfile = def.param("compareToProfile"); assertThat(compareToProfile.since()).isEqualTo("6.5"); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java index d6469fcb287..6faa393c465 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleQueryFactory.java @@ -34,6 +34,7 @@ import org.sonar.server.rule.index.RuleQuery; import static org.sonar.server.exceptions.NotFoundException.checkFound; import static org.sonar.server.rule.ws.EnumUtils.toEnums; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION; +import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_IMPACT_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_AVAILABLE_SINCE; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES; @@ -112,6 +113,7 @@ public class RuleQueryFactory { query.setCleanCodeAttributesCategories(request.paramAsStrings(PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES)); query.setImpactSeverities(request.paramAsStrings(PARAM_IMPACT_SEVERITIES)); query.setImpactSoftwareQualities(request.paramAsStrings(PARAM_IMPACT_SOFTWARE_QUALITIES)); + query.setActiveImpactSeverities(request.paramAsStrings(PARAM_ACTIVE_IMPACT_SEVERITIES)); String sortParam = request.param(WebService.Param.SORT); if (sortParam != null) { diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java index cde40bc0dc7..de38b488ab4 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RuleWsSupport.java @@ -51,6 +51,7 @@ import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; import static org.sonar.core.util.Uuids.UUID_EXAMPLE_02; import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVATION; +import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_IMPACT_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_AVAILABLE_SINCE; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES; @@ -190,6 +191,12 @@ public class RuleWsSupport { .setExampleValue(org.sonar.api.issue.impact.Severity.HIGH + "," + org.sonar.api.issue.impact.Severity.MEDIUM) .setPossibleValues(org.sonar.api.issue.impact.Severity.values()); + action.createParam(PARAM_ACTIVE_IMPACT_SEVERITIES) + .setSince("2025.1") + .setDescription("Comma-separated list of Activation Software Quality Severities, i.e the impact severity of rules in Quality profiles.") + .setExampleValue(org.sonar.api.issue.impact.Severity.HIGH + "," + org.sonar.api.issue.impact.Severity.MEDIUM) + .setPossibleValues(org.sonar.api.issue.impact.Severity.values()); + action.createParam(PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES) .setSince("10.2") .setDescription("Comma-separated list of Clean Code Attribute Categories") diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java index afef0698918..85f468ba652 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/RulesWsParameters.java @@ -50,6 +50,7 @@ public class RulesWsParameters { public static final String PARAM_IMPACT_SOFTWARE_QUALITIES = "impactSoftwareQualities"; public static final String PARAM_IMPACT_SEVERITIES = "impactSeverities"; + public static final String PARAM_ACTIVE_IMPACT_SEVERITIES = "active_impactSeverities"; public static final String PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES = "cleanCodeAttributeCategories"; public static final String PARAM_PRIORITIZED_RULE = "prioritizedRule"; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java index 1562c3ad6f5..e3fdcd222e0 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/ws/SearchAction.java @@ -68,6 +68,7 @@ import static org.sonar.api.server.ws.WebService.Param.PAGE; import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; import static org.sonar.server.es.SearchOptions.MAX_PAGE_SIZE; import static org.sonar.server.rule.index.RuleIndex.ALL_STATUSES_EXCEPT_REMOVED; +import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_IMPACT_SEVERITY; import static org.sonar.server.rule.index.RuleIndex.FACET_ACTIVE_SEVERITIES; import static org.sonar.server.rule.index.RuleIndex.FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY; import static org.sonar.server.rule.index.RuleIndex.FACET_CWE; @@ -85,6 +86,7 @@ import static org.sonar.server.rule.index.RuleIndex.FACET_STATUSES; import static org.sonar.server.rule.index.RuleIndex.FACET_TAGS; import static org.sonar.server.rule.index.RuleIndex.FACET_TYPES; import static org.sonar.server.rule.ws.RulesWsParameters.OPTIONAL_FIELDS; +import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_IMPACT_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_ACTIVE_SEVERITIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES; import static org.sonar.server.rule.ws.RulesWsParameters.PARAM_CWE; @@ -123,7 +125,8 @@ public class SearchAction implements RulesWsAction { FACET_SONARSOURCE_SECURITY, FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY, FACET_IMPACT_SEVERITY, - FACET_IMPACT_SOFTWARE_QUALITY + FACET_IMPACT_SOFTWARE_QUALITY, + FACET_ACTIVE_IMPACT_SEVERITY }; private final RuleQueryFactory ruleQueryFactory; @@ -194,7 +197,8 @@ public class SearchAction implements RulesWsAction { new Change("10.8", format("The parameters '%s','%s and '%s' are not deprecated anymore.", PARAM_SEVERITIES, PARAM_TYPES, PARAM_ACTIVE_SEVERITIES)), new Change("10.8", "The values 'severity' and 'types' for the 'facets' parameter are not deprecated anymore."), new Change("10.8", "The fields 'type' and 'severity' in the response are not deprecated anymore."), - new Change("10.8", "The value 'severity' for the 'f' parameter is not deprecated anymore.")); + new Change("10.8", "The value 'severity' for the 'f' parameter is not deprecated anymore."), + new Change("2025.2", format("The facet '%s' has been added.", FACET_ACTIVE_IMPACT_SEVERITY))); action.createParam(FACETS) .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") @@ -365,6 +369,7 @@ public class SearchAction implements RulesWsAction { facetValuesByFacetKey.put(FACET_CLEAN_CODE_ATTRIBUTE_CATEGORY, request.getCleanCodeAttributesCategories()); facetValuesByFacetKey.put(FACET_IMPACT_SOFTWARE_QUALITY, request.getImpactSoftwareQualities()); facetValuesByFacetKey.put(FACET_IMPACT_SEVERITY, request.getImpactSeverities()); + facetValuesByFacetKey.put(FACET_ACTIVE_IMPACT_SEVERITY, request.getActiveImpactSeverities()); for (String facetName : context.getFacets()) { facet.clear().setProperty(facetName); @@ -439,7 +444,8 @@ public class SearchAction implements RulesWsAction { .setOwaspTop10For2021(request.paramAsStrings(PARAM_OWASP_TOP_10_2021)) .setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25)) .setSonarsourceSecurity(request.paramAsStrings(PARAM_SONARSOURCE_SECURITY)) - .setPrioritizedRule(request.paramAsBoolean(PARAM_PRIORITIZED_RULE)); + .setPrioritizedRule(request.paramAsBoolean(PARAM_PRIORITIZED_RULE)) + .setActiveImpactSeverities(request.paramAsStrings(PARAM_ACTIVE_IMPACT_SEVERITIES)); } private static class SearchRequest { @@ -463,6 +469,7 @@ public class SearchAction implements RulesWsAction { private List<String> impactSeverities; private List<String> impactSoftwareQualities; private List<String> cleanCodeAttributesCategories; + private List<String> activeImpactSeverities; private Boolean prioritizedRule; private SearchRequest setActiveSeverities(List<String> activeSeverities) { @@ -650,5 +657,15 @@ public class SearchAction implements RulesWsAction { this.prioritizedRule = prioritizedRule; return this; } + + public SearchRequest setActiveImpactSeverities(@Nullable List<String> activeImpactSeverities) { + this.activeImpactSeverities = activeImpactSeverities; + return this; + } + + @CheckForNull + public List<String> getActiveImpactSeverities() { + return activeImpactSeverities; + } } } |