import org.sonar.api.utils.Duration;
import org.sonar.server.es.BaseDoc;
import org.sonar.server.permission.index.AuthorizationDoc;
+import org.sonar.server.security.SecurityStandards;
import static org.sonar.server.issue.index.IssueIndexDefinition.TYPE_ISSUE;
}
@CheckForNull
- public Collection<String> getSonarSourceSecurityCategories() {
- return getNullableField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY);
+ public SecurityStandards.SQCategory getSonarSourceSecurityCategory() {
+ String key = getNullableField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY);
+ return SecurityStandards.SQCategory.fromKey(key).orElse(null);
}
- public IssueDoc setSonarSourceSecurityCategories(@Nullable Collection<String> c) {
- setField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY, c);
+ public IssueDoc setSonarSourceSecurityCategory(@Nullable SecurityStandards.SQCategory c) {
+ setField(IssueIndexDefinition.FIELD_ISSUE_SONARSOURCE_SECURITY, c == null ? null : c.getKey());
return this;
}
}
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;
import org.sonar.server.security.SecurityStandards;
-import org.sonar.server.security.SecurityStandards.SQCategory;
import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.stream.Collectors.toList;
import static org.sonar.api.utils.DateUtils.longToDate;
import static org.sonar.db.DatabaseUtils.getLong;
import static org.sonar.db.rule.RuleDefinitionDto.deserializeSecurityStandardsString;
doc.setOwaspTop10(securityStandards.getOwaspTop10());
doc.setCwe(securityStandards.getCwe());
doc.setSansTop25(securityStandards.getSansTop25());
- doc.setSonarSourceSecurityCategories(securityStandards.getSq().stream().map(SQCategory::getKey).collect(toList()));
+ doc.setSonarSourceSecurityCategory(securityStandards.getSqCategory());
return doc;
}
import org.sonar.server.security.SecurityStandards;
import org.sonar.server.security.SecurityStandards.SQCategory;
-import static java.util.stream.Collectors.toList;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
}
@CheckForNull
- public Collection<String> getSonarSourceSecurityCategories() {
- return getNullableField(RuleIndexDefinition.FIELD_RULE_SONARSOURCE_SECURITY);
+ public SQCategory getSonarSourceSecurityCategory() {
+ String key = getNullableField(RuleIndexDefinition.FIELD_RULE_SONARSOURCE_SECURITY);
+ return SQCategory.fromKey(key).orElse(null);
}
- public RuleDoc setSonarSourceSecurityCategories(@Nullable Collection<String> c) {
- setField(RuleIndexDefinition.FIELD_RULE_SONARSOURCE_SECURITY, c);
+ public RuleDoc setSonarSourceSecurityCategory(@Nullable SQCategory sqCategory) {
+ setField(RuleIndexDefinition.FIELD_RULE_SONARSOURCE_SECURITY, sqCategory == null ? null : sqCategory.getKey());
return this;
}
return ReflectionToStringBuilder.toString(this);
}
- public static RuleDoc of(RuleForIndexingDto dto) {
- SecurityStandards securityStandards = SecurityStandards.fromSecurityStandards(dto.getSecurityStandards());
+ public static RuleDoc of(RuleForIndexingDto dto, SecurityStandards securityStandards) {
RuleDoc ruleDoc = new RuleDoc()
.setId(dto.getId())
.setKey(dto.getRuleKey().toString())
.setCwe(securityStandards.getCwe())
.setOwaspTop10(securityStandards.getOwaspTop10())
.setSansTop25(securityStandards.getSansTop25())
- .setSonarSourceSecurityCategories(securityStandards.getSq().stream().map(SQCategory::getKey).collect(toList()))
+ .setSonarSourceSecurityCategory(securityStandards.getSqCategory())
.setName(dto.getName())
.setRuleKey(dto.getPluginRuleKey())
.setSeverity(dto.getSeverityAsString())
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.es.EsQueueDto;
import org.sonar.db.es.RuleExtensionId;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.rule.RuleForIndexingDto;
import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.BulkIndexer.Size;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.IndexingResult;
import org.sonar.server.es.OneToOneResilientIndexingListener;
import org.sonar.server.es.ResilientIndexer;
+import org.sonar.server.security.SecurityStandards;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Stream.concat;
import static org.sonar.core.util.stream.MoreCollectors.toHashSet;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE_EXTENSION;
+import static org.sonar.server.security.SecurityStandards.SQ_CATEGORY_KEYS_ORDERING;
public class RuleIndexer implements ResilientIndexer {
-
private final EsClient esClient;
private final DbClient dbClient;
// index all definitions and system extensions
if (uninitializedIndexTypes.contains(TYPE_RULE)) {
dbClient.ruleDao().scrollIndexingRules(dbSession, dto -> {
- bulk.add(RuleDoc.of(dto).toIndexRequest());
+ bulk.add(ruleDocOf(dto).toIndexRequest());
bulk.add(RuleExtensionDoc.of(dto).toIndexRequest());
});
}
dbClient.ruleDao().scrollIndexingRulesByKeys(dbSession, ruleIds,
r -> {
- bulkIndexer.add(RuleDoc.of(r).toIndexRequest());
+ bulkIndexer.add(ruleDocOf(r).toIndexRequest());
bulkIndexer.add(RuleExtensionDoc.of(r).toIndexRequest());
ruleIds.remove(r.getId());
});
return Optional.of(bulkIndexer.stop());
}
+ private RuleDoc ruleDocOf(RuleForIndexingDto dto) {
+ SecurityStandards securityStandards = SecurityStandards.fromSecurityStandards(dto.getSecurityStandards());
+ if (!securityStandards.getIgnoredSQCategories().isEmpty()) {
+ Loggers.get(RuleIndexer.class).warn(
+ "Rule {} with CWEs '{}' maps to multiple SQ Security Categories: {}",
+ dto.getRuleKey(),
+ String.join(", ", securityStandards.getCwe()),
+ concat(Stream.of(securityStandards.getSqCategory()), securityStandards.getIgnoredSQCategories().stream())
+ .map(SecurityStandards.SQCategory::getKey)
+ .sorted(SQ_CATEGORY_KEYS_ORDERING)
+ .collect(joining(", ")));
+ }
+ return RuleDoc.of(dto, securityStandards);
+ }
+
private BulkIndexer createBulkIndexer(Size bulkSize, IndexingListener listener) {
return new BulkIndexer(esClient, TYPE_RULE, bulkSize, listener);
}
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;
-import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
-import org.sonar.core.util.stream.MoreCollectors;
import static java.util.Arrays.asList;
+import static java.util.Arrays.stream;
import static java.util.Collections.singleton;
+import static java.util.Collections.singletonList;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.core.util.stream.MoreCollectors.toSet;
+import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
import static org.sonar.server.security.SecurityStandards.VulnerabilityProbability.HIGH;
import static org.sonar.server.security.SecurityStandards.VulnerabilityProbability.LOW;
import static org.sonar.server.security.SecurityStandards.VulnerabilityProbability.MEDIUM;
FILE_MANIPULATION("file-manipulation", LOW),
OTHERS("others", LOW);
+ private static final Map<String, SQCategory> SQ_CATEGORY_BY_KEY = stream(values()).collect(uniqueIndex(SQCategory::getKey));
private final String key;
private final VulnerabilityProbability vulnerability;
public VulnerabilityProbability getVulnerability() {
return vulnerability;
}
+
+ public static Optional<SQCategory> fromKey(@Nullable String key) {
+ return Optional.ofNullable(key).map(SQ_CATEGORY_BY_KEY::get);
+ }
}
public static final Map<SQCategory, Set<String>> CWES_BY_SQ_CATEGORY = ImmutableMap.<SQCategory, Set<String>>builder()
.put(SQCategory.INSECURE_CONF, ImmutableSet.of("102", "215", "311", "315", "346", "614", "489", "942"))
.put(SQCategory.FILE_MANIPULATION, ImmutableSet.of("97", "73"))
.build();
- public static final Ordering<SQCategory> SQ_CATEGORY_ORDERING = Ordering.explicit(Arrays.stream(SQCategory.values()).collect(Collectors.toList()));
- public static final Ordering<String> SQ_CATEGORY_KEYS_ORDERING = Ordering.explicit(Arrays.stream(SQCategory.values()).map(SQCategory::getKey).collect(Collectors.toList()));
+ private static final Ordering<SQCategory> SQ_CATEGORY_ORDERING = Ordering.explicit(stream(SQCategory.values()).collect(Collectors.toList()));
+ public static final Ordering<String> SQ_CATEGORY_KEYS_ORDERING = Ordering.explicit(stream(SQCategory.values()).map(SQCategory::getKey).collect(Collectors.toList()));
private final Set<String> standards;
private final Set<String> cwe;
private final Set<String> owaspTop10;
private final Set<String> sansTop25;
- private final Set<SQCategory> sq;
+ private final SQCategory sqCategory;
+ private final Set<SQCategory> ignoredSQCategories;
- private SecurityStandards(Set<String> standards, Set<String> cwe, Set<String> owaspTop10, Set<String> sansTop25, Set<SQCategory> sq) {
+ private SecurityStandards(Set<String> standards, Set<String> cwe, Set<String> owaspTop10, Set<String> sansTop25, SQCategory sqCategory, Set<SQCategory> ignoredSQCategories) {
this.standards = standards;
this.cwe = cwe;
this.owaspTop10 = owaspTop10;
this.sansTop25 = sansTop25;
- this.sq = sq;
+ this.sqCategory = sqCategory;
+ this.ignoredSQCategories = ignoredSQCategories;
}
public Set<String> getStandards() {
return sansTop25;
}
- public Set<SQCategory> getSq() {
- return sq;
+ public SQCategory getSqCategory() {
+ return sqCategory;
+ }
+
+ public Set<SQCategory> getIgnoredSQCategories() {
+ return ignoredSQCategories;
}
+ /**
+ * @throws IllegalStateException if {@code securityStandards} maps to multiple {@link SQCategory SQCategories}
+ */
public static SecurityStandards fromSecurityStandards(Set<String> securityStandards) {
Set<String> standards = securityStandards.stream()
.filter(Objects::nonNull)
- .collect(MoreCollectors.toSet());
- Set<String> owaspTop10 = toOwaspTop10(standards);
+ .collect(toSet());
Set<String> cwe = toCwe(standards);
+ Set<String> owaspTop10 = toOwaspTop10(standards);
Set<String> sansTop25 = toSansTop25(cwe);
- Set<SQCategory> sq = toSQCategories(cwe);
- return new SecurityStandards(standards, cwe, owaspTop10, sansTop25, sq);
+ 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, owaspTop10, sansTop25, sqCategory, ignoredSQCategories);
}
private static Set<String> toOwaspTop10(Set<String> securityStandards) {
return securityStandards.stream()
.filter(s -> s.startsWith(OWASP_TOP10_PREFIX))
.map(s -> s.substring(OWASP_TOP10_PREFIX.length()))
- .collect(MoreCollectors.toSet());
+ .collect(toSet());
}
private static Set<String> toCwe(Collection<String> securityStandards) {
Set<String> result = securityStandards.stream()
.filter(s -> s.startsWith(CWE_PREFIX))
.map(s -> s.substring(CWE_PREFIX.length()))
- .collect(MoreCollectors.toSet());
+ .collect(toSet());
return result.isEmpty() ? singleton(UNKNOWN_STANDARD) : result;
}
.keySet()
.stream()
.filter(k -> cwe.stream().anyMatch(CWES_BY_SANS_TOP_25.get(k)::contains))
- .collect(MoreCollectors.toSet());
+ .collect(toSet());
}
- private static Set<SQCategory> toSQCategories(Collection<String> cwe) {
- Set<SQCategory> result = CWES_BY_SQ_CATEGORY
+ private static List<SQCategory> toSortedSQCategories(Collection<String> cwe) {
+ List<SQCategory> result = CWES_BY_SQ_CATEGORY
.keySet()
.stream()
.filter(k -> cwe.stream().anyMatch(CWES_BY_SQ_CATEGORY.get(k)::contains))
- .collect(MoreCollectors.toSet());
- return result.isEmpty() ? singleton(SQCategory.OTHERS) : result;
+ .sorted(SQ_CATEGORY_ORDERING)
+ .collect(toList());
+ return result.isEmpty() ? singletonList(SQCategory.OTHERS) : result;
}
}
assertThat(doc.getCwe()).containsExactlyInAnyOrder(SecurityStandards.UNKNOWN_STANDARD);
assertThat(doc.getOwaspTop10()).isEmpty();
assertThat(doc.getSansTop25()).isEmpty();
- assertThat(doc.getSonarSourceSecurityCategories()).containsOnly(SQCategory.OTHERS.getKey());
+ assertThat(doc.getSonarSourceSecurityCategory()).isEqualTo(SQCategory.OTHERS);
}
@Test
package org.sonar.server.rule.index;
import com.google.common.collect.ImmutableSet;
-import java.util.stream.Collectors;
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.EnumSet;
+import java.util.Random;
+import java.util.Set;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.rule.RuleMetadataDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.server.es.EsTester;
+import org.sonar.server.security.SecurityStandards;
+import org.sonar.server.security.SecurityStandards.SQCategory;
import static com.google.common.collect.Sets.newHashSet;
+import static java.lang.String.format;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
+import static java.util.stream.Collectors.joining;
+import static java.util.stream.Collectors.toSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE;
import static org.sonar.server.rule.index.RuleIndexDefinition.TYPE_RULE_EXTENSION;
+import static org.sonar.server.security.SecurityStandards.CWES_BY_SQ_CATEGORY;
+import static org.sonar.server.security.SecurityStandards.SQ_CATEGORY_KEYS_ORDERING;
+@RunWith(DataProviderRunner.class)
public class RuleIndexerTest {
@Rule
public EsTester es = EsTester.create();
-
@Rule
public DbTester dbTester = DbTester.create();
+ @Rule
+ public LogTester logTester = new LogTester();
private DbClient dbClient = dbTester.getDbClient();
private final RuleIndexer underTest = new RuleIndexer(es.client(), dbClient);
.get()
.getHits()
.getHits()[0]
- .getId()).isEqualTo(doc.getId());
+ .getId()).isEqualTo(doc.getId());
}
@Test
@Test
public void index_long_rule_description() {
- String description = IntStream.range(0, 100000).map(i -> i % 100).mapToObj(Integer::toString).collect(Collectors.joining(" "));
+ String description = IntStream.range(0, 100000).map(i -> i % 100).mapToObj(Integer::toString).collect(joining(" "));
RuleDefinitionDto rule = dbTester.rules().insert(r -> r.setDescription(description));
underTest.commitAndIndex(dbTester.getSession(), rule.getId());
assertThat(es.countDocuments(TYPE_RULE)).isEqualTo(1);
}
+
+ @Test
+ @UseDataProvider("twoDifferentCategoriesButOTHERS")
+ public void log_a_warning_if_hotspot_rule_maps_to_multiple_SQCategories(SQCategory sqCategory1, SQCategory sqCategory2) {
+ Set<String> standards = Stream.of(sqCategory1, sqCategory2)
+ .flatMap(t -> CWES_BY_SQ_CATEGORY.get(t).stream().map(e -> "cwe:" + e))
+ .collect(toSet());
+ SecurityStandards securityStandards = SecurityStandards.fromSecurityStandards(standards);
+ RuleDefinitionDto rule = dbTester.rules().insert(RuleTesting.newRule().setType(RuleType.SECURITY_HOTSPOT).setSecurityStandards(standards));
+ OrganizationDto organization = dbTester.organizations().insert();
+ underTest.commitAndIndex(dbTester.getSession(), rule.getId(), organization);
+
+ assertThat(logTester.getLogs()).hasSize(1);
+ assertThat(logTester.logs(LoggerLevel.WARN).get(0))
+ .isEqualTo(format(
+ "Rule %s with CWEs '%s' maps to multiple SQ Security Categories: %s",
+ rule.getKey(),
+ String.join(", ", securityStandards.getCwe()),
+ ImmutableSet.of(sqCategory1, sqCategory2).stream()
+ .map(SQCategory::getKey)
+ .sorted(SQ_CATEGORY_KEYS_ORDERING)
+ .collect(joining(", "))));
+ }
+
+ @DataProvider
+ public static Object[][] twoDifferentCategoriesButOTHERS() {
+ EnumSet<SQCategory> sqCategories = EnumSet.allOf(SQCategory.class);
+ sqCategories.remove(SQCategory.OTHERS);
+
+ // pick two random categories
+ Random random = new Random();
+ SQCategory sqCategory1 = sqCategories.toArray(new SQCategory[0])[random.nextInt(sqCategories.size())];
+ sqCategories.remove(sqCategory1);
+ SQCategory sqCategory2 = sqCategories.toArray(new SQCategory[0])[random.nextInt(sqCategories.size())];
+ return new Object[][] {
+ {sqCategory1, sqCategory2}
+ };
+ }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.security;
+
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.sonar.server.security.SecurityStandards.SQCategory;
+
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singleton;
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.security.SecurityStandards.CWES_BY_SQ_CATEGORY;
+import static org.sonar.server.security.SecurityStandards.SQ_CATEGORY_KEYS_ORDERING;
+import static org.sonar.server.security.SecurityStandards.fromSecurityStandards;
+
+public class SecurityStandardsTest {
+ @Test
+ public void fromSecurityStandards_from_empty_set_has_SQCategory_OTHERS() {
+ SecurityStandards securityStandards = fromSecurityStandards(emptySet());
+
+ assertThat(securityStandards.getStandards()).isEmpty();
+ assertThat(securityStandards.getSqCategory()).isEqualTo(SQCategory.OTHERS);
+ assertThat(securityStandards.getIgnoredSQCategories()).isEmpty();
+ }
+
+ @Test
+ public void fromSecurityStandards_from_empty_set_has_unkwown_cwe_standard() {
+ SecurityStandards securityStandards = fromSecurityStandards(emptySet());
+
+ assertThat(securityStandards.getStandards()).isEmpty();
+ assertThat(securityStandards.getCwe()).containsOnly("unknown");
+ }
+
+ @Test
+ public void fromSecurityStandards_from_empty_set_has_no_OwaspTop10_standard() {
+ SecurityStandards securityStandards = fromSecurityStandards(emptySet());
+
+ assertThat(securityStandards.getStandards()).isEmpty();
+ assertThat(securityStandards.getOwaspTop10()).isEmpty();
+ }
+
+ @Test
+ public void fromSecurityStandards_from_empty_set_has_no_SansTop25_standard() {
+ SecurityStandards securityStandards = fromSecurityStandards(emptySet());
+
+ assertThat(securityStandards.getStandards()).isEmpty();
+ assertThat(securityStandards.getSansTop25()).isEmpty();
+ }
+
+ @Test
+ public void fromSecurityStandards_finds_SQCategory_from_any_if_the_mapped_CWE_standard() {
+ CWES_BY_SQ_CATEGORY.forEach((sqCategory, cwes) -> {
+ cwes.forEach(cwe -> {
+ SecurityStandards securityStandards = fromSecurityStandards(singleton("cwe:" + cwe));
+
+ assertThat(securityStandards.getSqCategory()).isEqualTo(sqCategory);
+ });
+ });
+ }
+
+ @Test
+ public void fromSecurityStandards_finds_SQCategory_from_multiple_of_the_mapped_CWE_standard() {
+ CWES_BY_SQ_CATEGORY.forEach((sqCategory, cwes) -> {
+ SecurityStandards securityStandards = fromSecurityStandards(cwes.stream().map(t -> "cwe:" + t).collect(toSet()));
+
+ assertThat(securityStandards.getSqCategory()).isEqualTo(sqCategory);
+ });
+ }
+
+ @Test
+ public void fromSecurityStandards_finds_SQCategory_first_in_order_when_CWEs_map_to_multiple_SQCategories() {
+ EnumSet<SQCategory> sqCategories = EnumSet.allOf(SQCategory.class);
+ sqCategories.remove(SQCategory.OTHERS);
+
+ while (!sqCategories.isEmpty()) {
+ SQCategory expected = sqCategories.stream().min(SQ_CATEGORY_KEYS_ORDERING.onResultOf(SQCategory::getKey)).get();
+ SQCategory[] expectedIgnored = sqCategories.stream().filter(t -> t != expected).toArray(SQCategory[]::new);
+
+ Set<String> cwes = sqCategories.stream()
+ .flatMap(t -> CWES_BY_SQ_CATEGORY.get(t).stream().map(e -> "cwe:" + e))
+ .collect(Collectors.toSet());
+ SecurityStandards securityStandards = fromSecurityStandards(cwes);
+
+ assertThat(securityStandards.getSqCategory()).isEqualTo(expected);
+ assertThat(securityStandards.getIgnoredSQCategories()).containsOnly(expectedIgnored);
+
+ sqCategories.remove(expected);
+ }
+ }
+}
Hotspots.Rule.Builder ruleBuilder = Hotspots.Rule.newBuilder();
for (RuleDefinitionDto rule : rules) {
SecurityStandards securityStandards = SecurityStandards.fromSecurityStandards(rule.getSecurityStandards());
- SecurityStandards.SQCategory sqCategory = securityStandards.getSq()
- .stream()
- .min(SecurityStandards.SQ_CATEGORY_ORDERING)
- .orElse(SecurityStandards.SQCategory.OTHERS);
+ SecurityStandards.SQCategory sqCategory = securityStandards.getSqCategory();
ruleBuilder
.clear()
.setKey(rule.getKey().toString())