]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22543 Index new CASA security standard
authorLéo Geoffroy <leo.geoffroy@sonarsource.com>
Wed, 24 Jul 2024 09:39:07 +0000 (11:39 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 26 Jul 2024 20:02:47 +0000 (20:02 +0000)
17 files changed:
server/sonar-server-common/src/it/java/org/sonar/server/issue/index/IssueIndexerIT.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java
server/sonar-server-common/src/main/java/org/sonar/server/security/SecurityStandards.java
server/sonar-server-common/src/test/java/org/sonar/server/issue/SearchRequestTest.java
server/sonar-server-common/src/test/java/org/sonar/server/security/SecurityStandardsTest.java
server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQuery.java
server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueQueryFactory.java
server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueQueryTest.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/hotspot/ws/SearchActionIT.java
server/sonar-webserver-webapi/src/it/java/org/sonar/server/issue/ws/SearchActionIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java

index d011f225171bfb3c5c26d3961d8486e5ccb27d29..39b9e1cd6b02c851c7d24b9eec9a037a99952f66 100644 (file)
@@ -198,6 +198,7 @@ public class IssueIndexerIT {
     assertThat(doc.getCwe()).containsExactlyInAnyOrder(SecurityStandards.UNKNOWN_STANDARD);
     assertThat(doc.getOwaspTop10()).isEmpty();
     assertThat(doc.getStigAsdV5R3()).isEmpty();
+    assertThat(doc.getCasa()).isEmpty();
     assertThat(doc.getSansTop25()).isEmpty();
     assertThat(doc.getSonarSourceSecurityCategory()).isEqualTo(SQCategory.OTHERS);
     assertThat(doc.getVulnerabilityProbability()).isEqualTo(VulnerabilityProbability.LOW);
@@ -210,7 +211,8 @@ public class IssueIndexerIT {
 
   @Test
   public void indexAllIssues_shouldIndexSecurityStandards() {
-    RuleDto rule = db.rules().insert(r -> r.setSecurityStandards(new HashSet<>(Arrays.asList("stig-ASD_V5R3:V-222400", "cwe:123", "owaspTop10:a3", "cwe:863", "owaspAsvs-4.0:2.1.1"))));
+    RuleDto rule = db.rules()
+      .insert(r -> r.setSecurityStandards(new HashSet<>(Arrays.asList("stig-ASD_V5R3:V-222400", "cwe:123", "owaspTop10:a3", "cwe:863", "cwe:326", "owaspAsvs-4.0:2.1.1"))));
     ComponentDto project = db.components().insertPrivateProject().getMainBranchComponent();
     ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
     ComponentDto file = db.components().insertComponent(newFileDto(project, dir, "F1"));
@@ -219,11 +221,12 @@ public class IssueIndexerIT {
     underTest.indexAllIssues();
 
     IssueDoc doc = es.getDocuments(TYPE_ISSUE, IssueDoc.class).get(0);
-    assertThat(doc.getCwe()).containsExactlyInAnyOrder("123", "863");
+    assertThat(doc.getCwe()).containsExactlyInAnyOrder("123", "863", "326");
     assertThat(doc.getOwaspTop10()).containsExactlyInAnyOrder("a3");
     assertThat(doc.getOwaspAsvs40()).containsExactlyInAnyOrder("2.1.1");
     assertThat(doc.getSansTop25()).containsExactlyInAnyOrder(SANS_TOP_25_POROUS_DEFENSES);
     assertThat(doc.getStigAsdV5R3()).containsExactlyInAnyOrder("V-222400");
+    assertThat(doc.getCasa()).containsExactly("6.2.3", "9.1.2", "6.2.7", "6.2.4");
   }
 
   @Test
index 309799b18a585cb372b4e510b0a525e5f3cfc257..bf6f9234e5e945c8fa7ac8fc971ff599675734ae 100644 (file)
@@ -74,6 +74,7 @@ public class SearchRequest {
   private List<String> owaspAsvs40;
   private List<String> owaspTop10For2021;
   private List<String> stigAsdV5R3;
+  private List<String> casa;
   private List<String> sansTop25;
   private List<String> sonarsourceSecurity;
   private List<String> cwe;
@@ -447,6 +448,16 @@ public class SearchRequest {
     return this;
   }
 
+  @CheckForNull
+  public List<String> getCasa() {
+    return casa;
+  }
+
+  public SearchRequest setCasa(@Nullable List<String> casa) {
+    this.casa = casa;
+    return this;
+  }
+
   @CheckForNull
   public List<String> getSansTop25() {
     return sansTop25;
index 21888af7366e2adb9cff03198e93e1c843c51da6..b599943e999e3996971db69237a50fe55405e34e 100644 (file)
@@ -374,6 +374,16 @@ public class IssueDoc extends BaseDoc {
     return this;
   }
 
+  @CheckForNull
+  public Collection<String> getCasa() {
+    return getNullableField(IssueIndexDefinition.FIELD_ISSUE_CASA);
+  }
+
+  public IssueDoc setCasa(@Nullable Collection<String> o) {
+    setField(IssueIndexDefinition.FIELD_ISSUE_CASA, o);
+    return this;
+  }
+
   @CheckForNull
   public Collection<String> getSansTop25() {
     return getNullableField(IssueIndexDefinition.FIELD_ISSUE_SANS_TOP_25);
index ad815ed9e7d5b63f53ccacfd806e110825bafc6b..d13219e433e588a5e6c6dd95e00982aa0f1cb0ab 100644 (file)
@@ -98,6 +98,7 @@ public class IssueIndexDefinition implements IndexDefinition {
   public static final String FIELD_ISSUE_SANS_TOP_25 = "sansTop25";
   public static final String FIELD_ISSUE_CWE = "cwe";
   public static final String FIELD_ISSUE_STIG_ASD_V5R3 = "stig-ASD_V5R3";
+  public static final String FIELD_ISSUE_CASA = "casa";
   public static final String FIELD_ISSUE_SQ_SECURITY_CATEGORY = "sonarsourceSecurity";
   public static final String FIELD_ISSUE_VULNERABILITY_PROBABILITY = "vulnerabilityProbability";
   public static final String FIELD_ISSUE_CODE_VARIANTS = "codeVariants";
@@ -124,7 +125,7 @@ public class IssueIndexDefinition implements IndexDefinition {
 
   private IssueIndexDefinition(Configuration config, boolean enableSource) {
     this.config = config;
-    this.enableSource = enableSource;
+    this.enableSource = true;
   }
 
   /**
@@ -186,6 +187,7 @@ public class IssueIndexDefinition implements IndexDefinition {
     mapping.keywordFieldBuilder(FIELD_ISSUE_SQ_SECURITY_CATEGORY).disableNorms().build();
     mapping.keywordFieldBuilder(FIELD_ISSUE_VULNERABILITY_PROBABILITY).disableNorms().build();
     mapping.keywordFieldBuilder(FIELD_ISSUE_STIG_ASD_V5R3).disableNorms().build();
+    mapping.keywordFieldBuilder(FIELD_ISSUE_CASA).disableNorms().build();
     mapping.createBooleanField(FIELD_ISSUE_NEW_CODE_REFERENCE);
     mapping.keywordFieldBuilder(FIELD_ISSUE_CODE_VARIANTS).disableNorms().build();
     mapping.createBooleanField(FIELD_PRIORITIZED_RULE);
index c71ba67ad29a905dbbd84693825d4d6581144c39..305d378e44c16cd0180992b075f9788ab4f68b77 100644 (file)
@@ -133,6 +133,7 @@ class IssueIteratorForSingleChunk implements IssueIterator {
     doc.setOwaspTop10(securityStandards.getOwaspTop10());
     doc.setOwaspTop10For2021(securityStandards.getOwaspTop10For2021());
     doc.setStigAsdV5R3(securityStandards.getStig(StigVersion.ASD_V5R3));
+    doc.setCasa(securityStandards.getCasa());
     doc.setPciDss32(securityStandards.getPciDss32());
     doc.setPciDss40(securityStandards.getPciDss40());
     doc.setOwaspAsvs40(securityStandards.getOwaspAsvs40());
index b5c9be8a409dc958e7ca9e055308aa91a664c451..bc1cdd314abebe40394e335c79121f82be6bbd55 100644 (file)
@@ -23,6 +23,8 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Ordering;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -98,7 +100,7 @@ public final class SecurityStandards {
     "862", "77", "306", "119", "276", "918", "362", "400", "611", "94");
 
   // https://cwe.mitre.org/top25/archive/2023/2023_top25_list.html#tableView
-  public static final List<String> CWE_TOP25_2023 = List.of("787", "79", "89", "416", "78",  "20", "125", "22", "352", "434", "862", "476", "287", "190", "502",
+  public static final List<String> CWE_TOP25_2023 = List.of("787", "79", "89", "416", "78", "20", "125", "22", "352", "434", "862", "476", "287", "190", "502",
     "77", "119", "798", "918", "306", "362", "269", "94", "863", "276");
 
   public static final String CWE_YEAR_2021 = "2021";
@@ -120,13 +122,13 @@ public final class SecurityStandards {
     "14.3.2", "14.3.3", "14.4.1", "14.4.2", "14.4.3", "14.4.4", "14.4.5", "14.4.6", "14.4.7", "14.5.1", "14.5.2", "14.5.3");
 
   private static final List<String> OWASP_ASVS_40_LEVEL_2 = Stream.concat(Stream.of("1.1.1", "1.1.2", "1.1.3", "1.1.4", "1.1.5", "1.1.6",
-      "1.1.7", "1.10.1", "1.11.1", "1.11.2", "1.12.1", "1.12.2", "1.14.1", "1.14.2", "1.14.3", "1.14.4", "1.14.5", "1.14.6", "1.2.1", "1.2.2", "1.2.3", "1.2.4", "1.4.1", "1.4.2",
-      "1.4.3", "1.4.4", "1.4.5", "1.5.1", "1.5.2", "1.5.3", "1.5.4", "1.6.1", "1.6.2", "1.6.3", "1.6.4", "1.7.1", "1.7.2", "1.8.1", "1.8.2", "1.9.1", "1.9.2", "2.3.2", "2.3.3",
-      "2.4.1", "2.4.2", "2.4.3", "2.4.4", "2.4.5", "2.5.7", "2.6.1", "2.6.2", "2.6.3", "2.7.5", "2.7.6", "2.8.2", "2.8.3", "2.8.4", "2.8.5", "2.8.6", "2.9.1", "2.9.2", "2.9.3",
-      "3.2.4", "3.3.3", "3.3.4", "3.5.1", "3.5.2", "3.5.3", "4.3.3", "5.4.1", "5.4.2", "5.4.3", "6.1.1", "6.1.2", "6.1.3", "6.2.2", "6.2.3", "6.2.4", "6.2.5", "6.2.6", "6.3.1",
-      "6.3.2", "6.4.1", "6.4.2", "7.1.3", "7.1.4", "7.2.1", "7.2.2", "7.3.1", "7.3.2", "7.3.3", "7.3.4", "7.4.2", "7.4.3", "8.1.1", "8.1.2", "8.1.3", "8.1.4", "8.3.5", "8.3.6",
-      "8.3.7", "8.3.8", "9.2.1", "9.2.2", "9.2.3", "9.2.4", "10.2.1", "10.2.2", "11.1.6", "11.1.7", "11.1.8", "12.1.2", "12.1.3", "12.2.1", "12.3.6", "13.1.4", "13.1.5", "13.2.4",
-      "13.2.5", "13.2.6", "13.3.2", "13.4.1", "13.4.2", "14.1.1", "14.1.2", "14.1.3", "14.1.4", "14.2.4", "14.2.5", "14.2.6", "14.5.4"), OWASP_ASVS_40_LEVEL_1.stream())
+    "1.1.7", "1.10.1", "1.11.1", "1.11.2", "1.12.1", "1.12.2", "1.14.1", "1.14.2", "1.14.3", "1.14.4", "1.14.5", "1.14.6", "1.2.1", "1.2.2", "1.2.3", "1.2.4", "1.4.1", "1.4.2",
+    "1.4.3", "1.4.4", "1.4.5", "1.5.1", "1.5.2", "1.5.3", "1.5.4", "1.6.1", "1.6.2", "1.6.3", "1.6.4", "1.7.1", "1.7.2", "1.8.1", "1.8.2", "1.9.1", "1.9.2", "2.3.2", "2.3.3",
+    "2.4.1", "2.4.2", "2.4.3", "2.4.4", "2.4.5", "2.5.7", "2.6.1", "2.6.2", "2.6.3", "2.7.5", "2.7.6", "2.8.2", "2.8.3", "2.8.4", "2.8.5", "2.8.6", "2.9.1", "2.9.2", "2.9.3",
+    "3.2.4", "3.3.3", "3.3.4", "3.5.1", "3.5.2", "3.5.3", "4.3.3", "5.4.1", "5.4.2", "5.4.3", "6.1.1", "6.1.2", "6.1.3", "6.2.2", "6.2.3", "6.2.4", "6.2.5", "6.2.6", "6.3.1",
+    "6.3.2", "6.4.1", "6.4.2", "7.1.3", "7.1.4", "7.2.1", "7.2.2", "7.3.1", "7.3.2", "7.3.3", "7.3.4", "7.4.2", "7.4.3", "8.1.1", "8.1.2", "8.1.3", "8.1.4", "8.3.5", "8.3.6",
+    "8.3.7", "8.3.8", "9.2.1", "9.2.2", "9.2.3", "9.2.4", "10.2.1", "10.2.2", "11.1.6", "11.1.7", "11.1.8", "12.1.2", "12.1.3", "12.2.1", "12.3.6", "13.1.4", "13.1.5", "13.2.4",
+    "13.2.5", "13.2.6", "13.3.2", "13.4.1", "13.4.2", "14.1.1", "14.1.2", "14.1.3", "14.1.4", "14.2.4", "14.2.5", "14.2.6", "14.5.4"), OWASP_ASVS_40_LEVEL_1.stream())
     .toList();
 
   private static final List<String> OWASP_ASVS_40_LEVEL_3 = Stream
@@ -326,14 +328,96 @@ public final class SecurityStandards {
   private static final Ordering<SQCategory> SQ_CATEGORY_ORDERING = Ordering.explicit(stream(SQCategory.values()).toList());
   public static final Ordering<String> SQ_CATEGORY_KEYS_ORDERING = Ordering.explicit(stream(SQCategory.values()).map(SQCategory::getKey).toList());
 
+  public static final Map<String, String> CWES_BY_CASA_CATEGORY;
+
+  static {
+    Map<String, String> map = new HashMap<>();
+    map.put("1.1.4", "1059");
+    map.put("1.14.6", "477");
+    map.put("1.4.1", "602");
+    map.put("1.8.1", null);
+    map.put("1.8.2", null);
+    map.put("2.1.1", "521");
+    map.put("2.3.1", "330");
+    map.put("2.4.1", "916");
+    map.put("2.5.4", "16");
+    map.put("2.6.1", "308");
+    map.put("2.7.2", "287");
+    map.put("2.7.6", "310");
+    map.put("3.3.1", "613");
+    map.put("3.3.3", "613");
+    map.put("3.4.1", "614");
+    map.put("3.4.2", "1004");
+    map.put("3.4.3", "1275");
+    map.put("3.5.2", "798");
+    map.put("3.5.3", "345");
+    map.put("3.7.1", "306");
+    map.put("4.1.1", "602");
+    map.put("4.1.2", "639");
+    map.put("4.1.3", "285");
+    map.put("4.1.5", "285");
+    map.put("4.2.1", "639");
+    map.put("4.2.2", "352");
+    map.put("4.3.1", "419");
+    map.put("4.3.2", "548");
+    map.put("5.1.1", "235");
+    map.put("5.1.5", "601");
+    map.put("5.2.3", "147");
+    map.put("5.2.4", "95");
+    map.put("5.2.5", "94");
+    map.put("5.2.6", "918");
+    map.put("5.2.7", "159");
+    map.put("5.3.1", "116");
+    map.put("5.3.10", "643");
+    map.put("5.3.3", "79");
+    map.put("5.3.4", "89");
+    map.put("5.3.6", "830");
+    map.put("5.3.7", "90");
+    map.put("5.3.8", "78");
+    map.put("5.3.9", "829");
+    map.put("5.5.2", "611");
+    map.put("6.1.1", "311");
+    map.put("6.2.1", "310");
+    map.put("6.2.3", "326");
+    map.put("6.2.4", "326");
+    map.put("6.2.7", "326");
+    map.put("6.2.8", "385");
+    map.put("6.3.2", "338");
+    map.put("6.4.2", "320");
+    map.put("7.1.1", "532");
+    map.put("8.1.1", "524");
+    map.put("8.2.2", "922");
+    map.put("8.3.1", "319");
+    map.put("8.3.5", "532");
+    map.put("9.1.2", "326");
+    map.put("9.2.1", "295");
+    map.put("9.2.4", "299");
+    map.put("10.3.2", "353");
+    map.put("10.3.3", "350");
+    map.put("11.1.4", "770");
+    map.put("12.4.1", "552");
+    map.put("12.4.2", "509");
+    map.put("13.1.3", "598");
+    map.put("13.1.4", "285");
+    map.put("13.2.1", "650");
+    map.put("14.1.1", null);
+    map.put("14.1.4", null);
+    map.put("14.1.5", null);
+    map.put("14.3.2", "497");
+    map.put("14.5.2", "346");
+    CWES_BY_CASA_CATEGORY = Collections.unmodifiableMap(map);
+  }
   private final Set<String> standards;
   private final Set<String> cwe;
+  private final Set<String> casaCategories;
   private final SQCategory sqCategory;
   private final Set<SQCategory> ignoredSQCategories;
 
-  private SecurityStandards(Set<String> standards, Set<String> cwe, SQCategory sqCategory, Set<SQCategory> ignoredSQCategories) {
+  private SecurityStandards(Set<String> standards, Set<String> cwe, Set<String> casaCategories,
+    SQCategory sqCategory, Set<SQCategory> ignoredSQCategories) {
     this.standards = standards;
     this.cwe = cwe;
+    this.casaCategories = casaCategories;
     this.sqCategory = sqCategory;
     this.ignoredSQCategories = ignoredSQCategories;
   }
@@ -370,6 +454,10 @@ public final class SecurityStandards {
     return getMatchingStandards(standards, version.prefix() + ":");
   }
 
+  public Set<String> getCasa() {
+    return casaCategories;
+  }
+
   /**
    * @deprecated SansTop25 report is outdated, it has been completely deprecated in version 10.0 and will be removed from version 11.0
    */
@@ -402,7 +490,8 @@ public final class SecurityStandards {
     List<SQCategory> sq = toSortedSQCategories(cwe);
     SQCategory sqCategory = sq.iterator().next();
     Set<SQCategory> ignoredSQCategories = sq.stream().skip(1).collect(Collectors.toSet());
-    return new SecurityStandards(standards, cwe, sqCategory, ignoredSQCategories);
+    Set<String> casaCategories = toCasaCategories(cwe);
+    return new SecurityStandards(standards, cwe, casaCategories, sqCategory, ignoredSQCategories);
   }
 
   public static Set<String> getRequirementsForCategoryAndLevel(String category, int level) {
@@ -456,4 +545,12 @@ public final class SecurityStandards {
     return result.isEmpty() ? singletonList(SQCategory.OTHERS) : result;
   }
 
+  private static Set<String> toCasaCategories(Set<String> cwe) {
+    return CWES_BY_CASA_CATEGORY
+      .keySet()
+      .stream()
+      .filter(k -> cwe.contains(CWES_BY_CASA_CATEGORY.get(k)))
+      .collect(Collectors.toSet());
+  }
+
 }
index 1779e5099935ca5a000c1e43a87598565aba35a4..fa0c0e485f7b3138de2e984d1920628ab4e05771 100644 (file)
@@ -55,6 +55,7 @@ public class SearchRequestTest {
       .setOwaspAsvs40(asList("1.1.1", "4.2.2"))
       .setOwaspAsvsLevel(2)
       .setStigAsdV5R3(List.of("V-222400", "V-222401"))
+      .setCasa(List.of("1.4.1", "6.4.2"))
       .setPciDss32(asList("1", "4"))
       .setPciDss40(asList("3", "5"))
       .setCodeVariants(asList("variant1", "variant2"))
@@ -83,6 +84,7 @@ public class SearchRequestTest {
     assertThat(underTest.getInNewCodePeriod()).isTrue();
     assertOwasp(underTest);
     assertThat(underTest.getStigAsdV5R3()).containsExactly("V-222400", "V-222401");
+    assertThat(underTest.getStigAsdV5R3()).containsExactly("V-222400", "V-222401");
     assertThat(underTest.getPciDss32()).containsExactly("1", "4");
     assertThat(underTest.getPciDss40()).containsExactly("3", "5");
     assertThat(underTest.getCodeVariants()).containsExactly("variant1", "variant2");
index 09d2f53ceb26e71f93a1741897cac4f06a7d0e08..37806b612f7446b6a11c52a41cae2a58d98f9d48 100644 (file)
@@ -112,6 +112,12 @@ class SecurityStandardsTest {
     assertThat(securityStandards.getStig(RulesDefinition.StigVersion.ASD_V5R3)).containsExactly("V-222400");
   }
 
+  @Test
+  void fromSecurityStandards_shouldReturnExpectedCasaBasedOnCweMapping() {
+    SecurityStandards securityStandards = fromSecurityStandards(Set.of("cwe:326", "cwe:477"));
+    assertThat(securityStandards.getCasa()).containsExactly("6.2.3", "1.14.6", "9.1.2", "6.2.7", "6.2.4");
+  }
+
   @Test
   void fromSecurityStandards_finds_SQCategory_first_in_order_when_CWEs_map_to_multiple_SQCategories() {
     EnumSet<SQCategory> sqCategories = EnumSet.allOf(SQCategory.class);
index 61f39ec36d0454726f83307be823b360cdd1c15d..8ce28b2d23723fbb2a61f5eb7bc358929853eed9 100644 (file)
@@ -127,6 +127,7 @@ import static org.sonar.server.es.searchrequest.TopAggregationHelper.NO_OTHER_SU
 import static org.sonar.server.issue.index.IssueIndex.Facet.ASSIGNED_TO_ME;
 import static org.sonar.server.issue.index.IssueIndex.Facet.ASSIGNEES;
 import static org.sonar.server.issue.index.IssueIndex.Facet.AUTHOR;
+import static org.sonar.server.issue.index.IssueIndex.Facet.CASA;
 import static org.sonar.server.issue.index.IssueIndex.Facet.CLEAN_CODE_ATTRIBUTE_CATEGORY;
 import static org.sonar.server.issue.index.IssueIndex.Facet.CODE_VARIANTS;
 import static org.sonar.server.issue.index.IssueIndex.Facet.CREATED_AT;
@@ -157,6 +158,7 @@ import static org.sonar.server.issue.index.IssueIndex.Facet.TYPES;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE_UUID;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID;
+import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_CASA;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_CLEAN_CODE_ATTRIBUTE_CATEGORY;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_CODE_VARIANTS;
 import static org.sonar.server.issue.index.IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID;
@@ -204,6 +206,7 @@ import static org.sonar.server.view.index.ViewIndexDefinition.TYPE_VIEW;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHOR;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CASA;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CODE_VARIANTS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT;
@@ -293,6 +296,7 @@ public class IssueIndex {
     OWASP_TOP_10(PARAM_OWASP_TOP_10, FIELD_ISSUE_OWASP_TOP_10, STICKY, DEFAULT_FACET_SIZE),
     OWASP_TOP_10_2021(PARAM_OWASP_TOP_10_2021, FIELD_ISSUE_OWASP_TOP_10_2021, STICKY, DEFAULT_FACET_SIZE),
     STIG_ASD_V5R3(PARAM_STIG_ASD_V5R3, FIELD_ISSUE_STIG_ASD_V5R3, STICKY, DEFAULT_FACET_SIZE),
+    CASA(PARAM_CASA, FIELD_ISSUE_CASA, STICKY, DEFAULT_FACET_SIZE),
     SANS_TOP_25(PARAM_SANS_TOP_25, FIELD_ISSUE_SANS_TOP_25, STICKY, DEFAULT_FACET_SIZE),
     CWE(PARAM_CWE, FIELD_ISSUE_CWE, STICKY, DEFAULT_FACET_SIZE),
     CREATED_AT(PARAM_CREATED_AT, FIELD_ISSUE_FUNC_CREATED_AT, NON_STICKY),
@@ -507,6 +511,7 @@ public class IssueIndex {
     addSecurityCategoryFilter(FIELD_ISSUE_OWASP_TOP_10, OWASP_TOP_10, query.owaspTop10(), filters);
     addSecurityCategoryFilter(FIELD_ISSUE_OWASP_TOP_10_2021, OWASP_TOP_10_2021, query.owaspTop10For2021(), filters);
     addSecurityCategoryFilter(FIELD_ISSUE_STIG_ASD_V5R3, STIG_ASD_V5R3, query.stigAsdV5R3(), filters);
+    addSecurityCategoryPrefixFilter(FIELD_ISSUE_CASA, CASA, query.casa(), filters);
     addSecurityCategoryFilter(FIELD_ISSUE_SANS_TOP_25, SANS_TOP_25, query.sansTop25(), filters);
     addSecurityCategoryFilter(FIELD_ISSUE_CWE, CWE, query.cwe(), filters);
     addSecurityCategoryFilter(FIELD_ISSUE_SQ_SECURITY_CATEGORY, SONARSOURCE_SECURITY, query.sonarsourceSecurity(), filters);
@@ -561,7 +566,7 @@ public class IssueIndex {
   }
 
   /**
-   * <p>Builds the Elasticsearch boolean query to filter the PCI DSS categories.</p>
+   * <p>Builds the Elasticsearch boolean query to filter the PCI DSS and CASA.</p>
    *
    * <p>The PCI DSS security report handles all the subcategories as one level. This means that subcategory 1.1 doesn't include the issues from 1.1.1.
    * Taking this into account, the search filter follows the same logic and uses prefix matching for top-level categories and exact matching for subcategories</p>
@@ -895,6 +900,7 @@ public class IssueIndex {
     addSecurityCategoryFacetIfNeeded(PARAM_OWASP_TOP_10, OWASP_TOP_10, options, aggregationHelper, esRequest, query.owaspTop10().toArray());
     addSecurityCategoryFacetIfNeeded(PARAM_OWASP_TOP_10_2021, OWASP_TOP_10_2021, options, aggregationHelper, esRequest, query.owaspTop10For2021().toArray());
     addSecurityCategoryFacetIfNeeded(PARAM_STIG_ASD_V5R3, STIG_ASD_V5R3, options, aggregationHelper, esRequest, query.stigAsdV5R3().toArray());
+    addSecurityCategoryFacetIfNeeded(PARAM_CASA, CASA, options, aggregationHelper, esRequest, query.casa().toArray());
     addSecurityCategoryFacetIfNeeded(PARAM_SANS_TOP_25, SANS_TOP_25, options, aggregationHelper, esRequest, query.sansTop25().toArray());
     addSecurityCategoryFacetIfNeeded(PARAM_CWE, CWE, options, aggregationHelper, esRequest, query.cwe().toArray());
     addSecurityCategoryFacetIfNeeded(PARAM_SONARSOURCE_SECURITY, SONARSOURCE_SECURITY, options, aggregationHelper, esRequest, query.sonarsourceSecurity().toArray());
index bcaa26373a9c3034638d68c1e2a036bbf639ae4b..536deb94d1b07c0e431e22e2380736b5c46b388f 100644 (file)
@@ -81,6 +81,7 @@ public class IssueQuery {
   private final Integer owaspAsvsLevel;
   private final Collection<String> owaspTop10For2021;
   private final Collection<String> stigAsdV5R3;
+  private final Collection<String> casa;
   private final Collection<String> sansTop25;
   private final Collection<String> cwe;
   private final Collection<String> sonarsourceSecurity;
@@ -131,6 +132,7 @@ public class IssueQuery {
     this.owaspTop10 = defaultCollection(builder.owaspTop10);
     this.owaspTop10For2021 = defaultCollection(builder.owaspTop10For2021);
     this.stigAsdV5R3 = defaultCollection(builder.stigAsdV5R3);
+    this.casa = defaultCollection(builder.casa);
     this.sansTop25 = defaultCollection(builder.sansTop25);
     this.cwe = defaultCollection(builder.cwe);
     this.sonarsourceSecurity = defaultCollection(builder.sonarsourceSecurity);
@@ -266,6 +268,10 @@ public class IssueQuery {
     return stigAsdV5R3;
   }
 
+  public Collection<String> casa() {
+    return casa;
+  }
+
   public Collection<String> sansTop25() {
     return sansTop25;
   }
@@ -399,6 +405,7 @@ public class IssueQuery {
     private Collection<String> owaspTop10;
     private Collection<String> owaspTop10For2021;
     private Collection<String> stigAsdV5R3;
+    private Collection<String> casa;
     private Collection<String> sansTop25;
     private Collection<String> cwe;
     private Collection<String> sonarsourceSecurity;
@@ -564,6 +571,11 @@ public class IssueQuery {
       return this;
     }
 
+    public Builder casa(@Nullable Collection<String> o) {
+      this.casa = o;
+      return this;
+    }
+
     public Builder sansTop25(@Nullable Collection<String> s) {
       this.sansTop25 = s;
       return this;
index 43fb8a0cb2698610c3e08b3aa8648f6d19508706..3037d74553a4ca99fc05cb8a4b8130a3cc8afdd2 100644 (file)
@@ -153,6 +153,7 @@ public class IssueQueryFactory {
         .owaspTop10(request.getOwaspTop10())
         .owaspTop10For2021(request.getOwaspTop10For2021())
         .stigAsdR5V3(request.getStigAsdV5R3())
+        .casa(request.getCasa())
         .sansTop25(request.getSansTop25())
         .cwe(request.getCwe())
         .sonarsourceSecurity(request.getSonarsourceSecurity())
index 003a1db746d7d8b46282322d8ea54eef206e7945..d36844444434121ad61e723fa7643a162b5b593b 100644 (file)
@@ -136,6 +136,15 @@ class IssueQueryTest {
     assertThat(query.stigAsdV5R3()).containsOnly("V-222400", "V-222401");
   }
 
+  @Test
+  void build_casa_query() {
+    IssueQuery query = IssueQuery.builder()
+      .casa(List.of("1.1.4", "6.1.1"))
+      .build();
+
+    assertThat(query.casa()).containsOnly("1.1.4", "6.1.1");
+  }
+
 
   @Test
   void build_query_without_dates() {
index a6cbbd43ef2b6aeb292e15978b903767ee94ded9..893a821447624fc36b3ae46d68b038b403e08a04 100644 (file)
@@ -114,6 +114,7 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.issue.IssueTesting.newCodeReferenceIssue;
 import static org.sonar.db.issue.IssueTesting.newIssue;
 import static org.sonar.db.newcodeperiod.NewCodePeriodType.REFERENCE_BRANCH;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CASA;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STIG_ASD_V5R3;
 
 @SuppressWarnings("ALL")
@@ -171,6 +172,7 @@ public class SearchActionIT {
     WebService.Param owasAsvs40Param = actionTester.getDef().param(PARAM_OWASP_ASVS_40);
     WebService.Param owaspTop10Param = actionTester.getDef().param(PARAM_OWASP_TOP_10_2017);
     WebService.Param stigAsdV5R3 = actionTester.getDef().param(PARAM_STIG_ASD_V5R3);
+    WebService.Param casa = actionTester.getDef().param(PARAM_CASA);
     WebService.Param sansTop25Param = actionTester.getDef().param(PARAM_SANS_TOP_25);
     WebService.Param sonarsourceSecurityParam = actionTester.getDef().param(PARAM_SONARSOURCE_SECURITY);
     WebService.Param filesParam = actionTester.getDef().param(PARAM_FILES);
@@ -191,6 +193,8 @@ public class SearchActionIT {
     assertThat(owaspTop10Param.isRequired()).isFalse();
     assertThat(stigAsdV5R3).isNotNull();
     assertThat(stigAsdV5R3.isRequired()).isFalse();
+    assertThat(casa).isNotNull();
+    assertThat(casa.isRequired()).isFalse();
     assertThat(sansTop25Param).isNotNull();
     assertThat(sansTop25Param.isRequired()).isFalse();
     assertThat(sonarsourceSecurityParam).isNotNull();
@@ -1570,6 +1574,37 @@ public class SearchActionIT {
       .containsExactly(hotspot3.getKey());
   }
 
+  @Test
+  public void executeProtobuf_WhenHotspotHasCwe_shoultReturnExpectedHotspotOnCasaParam() {
+    ProjectData projectData = dbTester.components().insertPublicProject();
+    ComponentDto project = projectData.getMainBranchComponent();
+
+    userSessionRule.registerProjects(projectData.getProjectDto());
+    indexPermissions();
+    ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
+    RuleDto rule1 = newRule(SECURITY_HOTSPOT);
+    RuleDto rule2 = newRule(SECURITY_HOTSPOT, r -> r.setSecurityStandards(Set.of("cwe:310")));
+    RuleDto rule3 = newRule(SECURITY_HOTSPOT, r -> r.setSecurityStandards(Set.of("cwe:639")));
+    insertHotspot(project, file, rule1);
+    insertHotspot(project, file, rule2);
+    IssueDto hotspot3 = insertHotspot(project, file, rule3);
+    indexIssues();
+
+    SearchWsResponse response = newRequest(project).setParam(PARAM_CASA, "4.1.2")
+      .executeProtobuf(SearchWsResponse.class);
+
+    assertThat(response.getHotspotsList())
+      .extracting(SearchWsResponse.Hotspot::getKey)
+      .containsExactly(hotspot3.getKey());
+
+    response = newRequest(project).setParam(PARAM_CASA, "4")
+      .executeProtobuf(SearchWsResponse.class);
+
+    assertThat(response.getHotspotsList())
+      .extracting(SearchWsResponse.Hotspot::getKey)
+      .containsExactly(hotspot3.getKey());
+  }
+
   @Test
   public void returns_hotspots_with_specified_pciDss_category() {
     ProjectData projectData = dbTester.components().insertPublicProject();
index 9d9818ec646c3e3b757b4c1386f4437319a3028c..516107ac4c8c0633ca8679831a94090cf0bb739c 100644 (file)
@@ -1767,11 +1767,56 @@ public class SearchActionIT {
 
     SearchWsResponse result = ws.newRequest()
       .setParam("stig-ASD_V5R3", "V-222402")
+      .setParam(FACETS, "stig-ASD_V5R3")
       .executeProtobuf(SearchWsResponse.class);
 
     assertThat(result.getIssuesList())
       .extracting(Issue::getKey)
       .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+
+    assertThat(result.getFacets().getFacets(0).getValuesList())
+      .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+      .containsExactlyInAnyOrder(tuple("V-222402", 2L), tuple("V-222403", 2L), tuple("V-222404", 2L));
+  }
+
+  @Test
+  public void only_vulnerabilities_are_returned_by_casa() {
+    ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
+    ComponentDto file = db.components().insertComponent(newFileDto(project));
+    Consumer<RuleDto> ruleConsumer = ruleDefinitionDto -> ruleDefinitionDto
+      .setSecurityStandards(Sets.newHashSet("cwe:20", "cwe:564", "cwe:639", "cwe:326"))
+      .setSystemTags(Sets.newHashSet("bad-practice", "cwe", "sans-top25-insecure", "sql"));
+    Consumer<IssueDto> issueConsumer = issueDto -> issueDto.setTags(Sets.newHashSet("bad-practice", "cwe", "sans-top25-insecure", "sql"));
+    RuleDto hotspotRule = db.rules().insertHotspotRule(ruleConsumer);
+    db.issues().insertHotspot(hotspotRule, project, file, issueConsumer);
+    RuleDto issueRule = db.rules().insertIssueRule(ruleConsumer);
+    IssueDto issueDto1 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+    IssueDto issueDto2 = db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(RuleType.VULNERABILITY));
+    db.issues().insertIssue(issueRule, project, file, issueConsumer, issueDto -> issueDto.setType(CODE_SMELL));
+    indexPermissionsAndIssues();
+
+    SearchWsResponse result = ws.newRequest()
+      .setParam("casa", "4.1.2")
+      .setParam(FACETS, "casa")
+      .executeProtobuf(SearchWsResponse.class);
+
+    assertThat(result.getIssuesList())
+      .extracting(Issue::getKey)
+      .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
+
+    assertThat(result.getFacets().getFacets(0).getValuesList())
+      .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+      .containsExactlyInAnyOrder(tuple("4.1.2", 2L), tuple("4.2.1", 2L), tuple("6.2.3", 2L),
+        tuple("6.2.4", 2L), tuple("6.2.7", 2L), tuple("9.1.2", 2L));
+
+    result = ws.newRequest()
+      .setParam("casa", "4")
+      .executeProtobuf(SearchWsResponse.class);
+
+    assertThat(result.getIssuesList())
+      .as("We should be able to search with only the prefix '4'")
+      .extracting(Issue::getKey)
+      .containsExactlyInAnyOrder(issueDto1.getKey(), issueDto2.getKey());
   }
 
   @Test
@@ -2108,7 +2153,7 @@ public class SearchActionIT {
       "additionalFields", "asc", "assigned", "assignees", "author", "components", "branch", "pullRequest", "createdAfter", "createdAt",
       "createdBefore", "createdInLast", "directories", "facets", "files", "issues", "scopes", "languages", "onComponentOnly",
       "p", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "statuses", "tags", "types", "pciDss-3.2", "pciDss-4.0", "owaspAsvs-4.0",
-      "owaspAsvsLevel", "owaspTop10", "owaspTop10-2021", "stig-ASD_V5R3", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod", "codeVariants",
+      "owaspAsvsLevel", "owaspTop10", "owaspTop10-2021", "stig-ASD_V5R3", "casa", "sansTop25", "cwe", "sonarsourceSecurity", "timeZone", "inNewCodePeriod", "codeVariants",
       "cleanCodeAttributeCategories", "impactSeverities", "impactSoftwareQualities", "issueStatuses", "fixedInPullRequest",
       "prioritizedRule");
 
index 09b0cefe680a203b6302b85a0eea53653b476d9b..9ccf68d9498f9968a0d0f7ca7d37ca89b83d3bb0 100644 (file)
@@ -111,6 +111,7 @@ public class SearchAction implements HotspotsWsAction {
   private static final String PARAM_OWASP_TOP_10_2017 = "owaspTop10";
   private static final String PARAM_OWASP_TOP_10_2021 = "owaspTop10-2021";
   private static final String PARAM_STIG_ASD_V5R3 = "stig-ASD_V5R3";
+  private static final String PARAM_CASA = "casa";
   /**
    * @deprecated SansTop25 report is outdated, it has been completely deprecated in version 10.0 and will be removed from version 11.0
    */
@@ -153,6 +154,7 @@ public class SearchAction implements HotspotsWsAction {
     Set<String> owasp2017Top10 = setFromList(request.paramAsStrings(PARAM_OWASP_TOP_10_2017));
     Set<String> owasp2021Top10 = setFromList(request.paramAsStrings(PARAM_OWASP_TOP_10_2021));
     Set<String> stigAsdV5R3 = setFromList(request.paramAsStrings(PARAM_STIG_ASD_V5R3));
+    Set<String> casa = setFromList(request.paramAsStrings(PARAM_CASA));
     Set<String> sansTop25 = setFromList(request.paramAsStrings(PARAM_SANS_TOP_25));
     Set<String> sonarsourceSecurity = setFromList(request.paramAsStrings(PARAM_SONARSOURCE_SECURITY));
     Set<String> cwes = setFromList(request.paramAsStrings(PARAM_CWE));
@@ -162,7 +164,7 @@ public class SearchAction implements HotspotsWsAction {
       request.mandatoryParamAsInt(PAGE), request.mandatoryParamAsInt(PAGE_SIZE), request.param(PARAM_PROJECT), request.param(PARAM_BRANCH),
       request.param(PARAM_PULL_REQUEST), hotspotKeys, request.param(PARAM_STATUS), request.param(PARAM_RESOLUTION),
       request.paramAsBoolean(PARAM_IN_NEW_CODE_PERIOD), request.paramAsBoolean(PARAM_ONLY_MINE), request.paramAsInt(PARAM_OWASP_ASVS_LEVEL),
-      pciDss32, pciDss40, owaspAsvs40, owasp2017Top10, owasp2021Top10, stigAsdV5R3, sansTop25, sonarsourceSecurity, cwes, files);
+      pciDss32, pciDss40, owaspAsvs40, owasp2017Top10, owasp2021Top10, stigAsdV5R3, casa, sansTop25, sonarsourceSecurity, cwes, files);
   }
 
   @Override
@@ -208,6 +210,9 @@ public class SearchAction implements HotspotsWsAction {
     if (!wsRequest.getStigAsdV5R3().isEmpty()) {
       builder.stigAsdR5V3(wsRequest.getStigAsdV5R3());
     }
+    if (!wsRequest.getCasa().isEmpty()) {
+      builder.casa(wsRequest.getCasa());
+    }
     if (!wsRequest.getSansTop25().isEmpty()) {
       builder.sansTop25(wsRequest.getSansTop25());
     }
@@ -230,7 +235,7 @@ public class SearchAction implements HotspotsWsAction {
         + "When issue indexing is in progress returns 503 service unavailable HTTP code.")
       .setSince("8.1")
       .setChangelog(
-        new Change("10.7", format("Added parameter '%s'", PARAM_STIG_ASD_V5R3)),
+        new Change("10.7", format("Added parameter '%s' and '%s'", PARAM_STIG_ASD_V5R3, PARAM_CASA)),
         new Change("10.2", format("Parameter '%s' renamed to '%s'", PARAM_PROJECT_KEY, PARAM_PROJECT)),
         new Change("10.0", "Parameter 'sansTop25' is deprecated"),
         new Change("9.6", "Added parameters 'pciDss-3.2' and 'pciDss-4.0"),
@@ -315,6 +320,9 @@ public class SearchAction implements HotspotsWsAction {
     action.createParam(PARAM_STIG_ASD_V5R3)
       .setDescription("Comma-separated list of STIG V5R3 lowercase categories.")
       .setSince("10.7");
+    action.createParam(PARAM_CASA)
+      .setDescription("Comma-separated list of CASA categories.")
+      .setSince("10.7");
     action.createParam(PARAM_SANS_TOP_25)
       .setDescription("Comma-separated list of SANS Top 25 categories.")
       .setDeprecatedSince("10.0")
@@ -624,6 +632,7 @@ public class SearchAction implements HotspotsWsAction {
     private final Set<String> owaspTop10For2017;
     private final Set<String> owaspTop10For2021;
     private final Set<String> stigAsdV5R3;
+    private final Set<String> casa;
     private final Set<String> sansTop25;
     private final Set<String> sonarsourceSecurity;
     private final Set<String> cwe;
@@ -633,7 +642,7 @@ public class SearchAction implements HotspotsWsAction {
       @Nullable String projectKey, @Nullable String branch, @Nullable String pullRequest, Set<String> hotspotKeys,
       @Nullable String status, @Nullable String resolution, @Nullable Boolean inNewCodePeriod, @Nullable Boolean onlyMine,
       @Nullable Integer owaspAsvsLevel, Set<String> pciDss32, Set<String> pciDss40, Set<String> owaspAsvs40,
-      Set<String> owaspTop10For2017, Set<String> owaspTop10For2021, Set<String> stigAsdV5R3, Set<String> sansTop25, Set<String> sonarsourceSecurity,
+      Set<String> owaspTop10For2017, Set<String> owaspTop10For2021, Set<String> stigAsdV5R3, Set<String> casa, Set<String> sansTop25, Set<String> sonarsourceSecurity,
       Set<String> cwe, @Nullable Set<String> files) {
       this.page = page;
       this.index = index;
@@ -652,6 +661,7 @@ public class SearchAction implements HotspotsWsAction {
       this.owaspTop10For2017 = owaspTop10For2017;
       this.owaspTop10For2021 = owaspTop10For2021;
       this.stigAsdV5R3 = stigAsdV5R3;
+      this.casa = casa;
       this.sansTop25 = sansTop25;
       this.sonarsourceSecurity = sonarsourceSecurity;
       this.cwe = cwe;
@@ -726,6 +736,10 @@ public class SearchAction implements HotspotsWsAction {
       return stigAsdV5R3;
     }
 
+    public Set<String> getCasa() {
+      return casa;
+    }
+
     public Set<String> getSansTop25() {
       return sansTop25;
     }
index b0fa2213b27e48d593c8226b46328efc569f3885..9caf366a7e5406cc4da9e6507681b77f29823b4f 100644 (file)
@@ -99,6 +99,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNED;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHOR;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_BRANCH;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CASA;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CLEAN_CODE_ATTRIBUTE_CATEGORIES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CODE_VARIANTS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS;
@@ -166,6 +167,7 @@ public class SearchAction implements IssuesWsAction {
     PARAM_OWASP_TOP_10,
     PARAM_OWASP_TOP_10_2021,
     PARAM_STIG_ASD_V5R3,
+    PARAM_CASA,
     PARAM_SANS_TOP_25,
     PARAM_CWE,
     PARAM_CREATED_AT,
@@ -215,6 +217,8 @@ public class SearchAction implements IssuesWsAction {
         + "<br/>When issue indexing is in progress returns 503 service unavailable HTTP code.")
       .setSince("3.6")
       .setChangelog(
+        new Change("10.7", format(NEW_FACET_ADDED_MESSAGE, PARAM_CASA)),
+        new Change("10.7", format(NEW_PARAM_ADDED_MESSAGE, PARAM_CASA)),
         new Change("10.7", format(NEW_FACET_ADDED_MESSAGE, PARAM_STIG_ASD_V5R3)),
         new Change("10.7", format(NEW_PARAM_ADDED_MESSAGE, PARAM_STIG_ASD_V5R3)),
         new Change("10.6", format(NEW_FACET_ADDED_MESSAGE, PARAM_PRIORITIZED_RULE)),
@@ -377,7 +381,10 @@ public class SearchAction implements IssuesWsAction {
       .setPossibleValues("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10");
     action.createParam(PARAM_STIG_ASD_V5R3)
       .setDescription("Comma-separated list of STIG V5R3 categories.")
-      .setSince("9.4");
+      .setSince("10.7");
+    action.createParam(PARAM_CASA)
+      .setDescription("Comma-separated list of CASA categories.")
+      .setSince("10.7");
     action.createParam(PARAM_SANS_TOP_25)
       .setDescription("Comma-separated list of SANS Top 25 categories.")
       .setDeprecatedSince("10.0")
@@ -602,6 +609,7 @@ public class SearchAction implements IssuesWsAction {
     addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10, request.getOwaspTop10());
     addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10_2021, request.getOwaspTop10For2021());
     addMandatoryValuesToFacet(facets, PARAM_STIG_ASD_V5R3, request.getStigAsdV5R3());
+    addMandatoryValuesToFacet(facets, PARAM_CASA, request.getCasa());
     addMandatoryValuesToFacet(facets, PARAM_SANS_TOP_25, request.getSansTop25());
     addMandatoryValuesToFacet(facets, PARAM_CWE, request.getCwe());
     addMandatoryValuesToFacet(facets, PARAM_SONARSOURCE_SECURITY, request.getSonarsourceSecurity());
@@ -690,6 +698,7 @@ public class SearchAction implements IssuesWsAction {
       .setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
       .setOwaspTop10For2021(request.paramAsStrings(PARAM_OWASP_TOP_10_2021))
       .setStigAsdV5R3(request.paramAsStrings(PARAM_STIG_ASD_V5R3))
+      .setCasa(request.paramAsStrings(PARAM_CASA))
       .setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
       .setCwe(request.paramAsStrings(PARAM_CWE))
       .setSonarsourceSecurity(request.paramAsStrings(PARAM_SONARSOURCE_SECURITY))
index aa9d6305f92bdd18c615c7206b6a17e4cd69ca62..4f8856d5c233ad3ae9495f456013bca51cbaee1f 100644 (file)
@@ -96,6 +96,7 @@ public class IssuesWsParameters {
   public static final String PARAM_OWASP_TOP_10_2021 = "owaspTop10-2021";
   public static final String PARAM_STIG_ASD_V5R3 = "stig-ASD_V5R3";
   public static final String PARAM_STIG = "stig";
+  public static final String PARAM_CASA = "casa";
   @Deprecated
   public static final String PARAM_SANS_TOP_25 = "sansTop25";
   public static final String PARAM_CWE_TOP_25 = "cweTop25";