Browse Source

SONAR-10980 Index security standards in ES and update issues/search WS

tags/7.5
Julien HENRY 6 years ago
parent
commit
d1c074ce4e

+ 36
- 0
server/sonar-server-common/src/main/java/org/sonar/server/issue/IssueQuery.java View File

private final Collection<String> languages; private final Collection<String> languages;
private final Collection<String> tags; private final Collection<String> tags;
private final Collection<String> types; private final Collection<String> types;
private final Collection<String> owaspTop10;
private final Collection<String> sansTop25;
private final Collection<String> cwe;
private final Map<String, PeriodStart> createdAfterByProjectUuids; private final Map<String, PeriodStart> createdAfterByProjectUuids;
private final Boolean onComponentOnly; private final Boolean onComponentOnly;
private final Boolean assigned; private final Boolean assigned;
this.languages = defaultCollection(builder.languages); this.languages = defaultCollection(builder.languages);
this.tags = defaultCollection(builder.tags); this.tags = defaultCollection(builder.tags);
this.types = defaultCollection(builder.types); this.types = defaultCollection(builder.types);
this.owaspTop10 = defaultCollection(builder.owaspTop10);
this.sansTop25 = defaultCollection(builder.sansTop25);
this.cwe = defaultCollection(builder.cwe);
this.createdAfterByProjectUuids = defaultMap(builder.createdAfterByProjectUuids); this.createdAfterByProjectUuids = defaultMap(builder.createdAfterByProjectUuids);
this.onComponentOnly = builder.onComponentOnly; this.onComponentOnly = builder.onComponentOnly;
this.assigned = builder.assigned; this.assigned = builder.assigned;
return types; return types;
} }


public Collection<String> owaspTop10() {
return owaspTop10;
}

public Collection<String> sansTop25() {
return sansTop25;
}

public Collection<String> cwe() {
return cwe;
}

public Map<String, PeriodStart> createdAfterByProjectUuids() { public Map<String, PeriodStart> createdAfterByProjectUuids() {
return createdAfterByProjectUuids; return createdAfterByProjectUuids;
} }
private Collection<String> languages; private Collection<String> languages;
private Collection<String> tags; private Collection<String> tags;
private Collection<String> types; private Collection<String> types;
private Collection<String> owaspTop10;
private Collection<String> sansTop25;
private Collection<String> cwe;
private Map<String, PeriodStart> createdAfterByProjectUuids; private Map<String, PeriodStart> createdAfterByProjectUuids;
private Boolean onComponentOnly = false; private Boolean onComponentOnly = false;
private Boolean assigned = null; private Boolean assigned = null;
return this; return this;
} }


public Builder owaspTop10(@Nullable Collection<String> o) {
this.owaspTop10 = o;
return this;
}

public Builder sansTop25(@Nullable Collection<String> s) {
this.sansTop25 = s;
return this;
}

public Builder cwe(@Nullable Collection<String> cwe) {
this.cwe = cwe;
return this;
}

public Builder createdAfterByProjectUuids(@Nullable Map<String, PeriodStart> createdAfterByProjectUuids) { public Builder createdAfterByProjectUuids(@Nullable Map<String, PeriodStart> createdAfterByProjectUuids) {
this.createdAfterByProjectUuids = createdAfterByProjectUuids; this.createdAfterByProjectUuids = createdAfterByProjectUuids;
return this; return this;

+ 33
- 0
server/sonar-server-common/src/main/java/org/sonar/server/issue/SearchRequest.java View File

private List<String> statuses; private List<String> statuses;
private List<String> tags; private List<String> tags;
private List<String> types; private List<String> types;
private List<String> owaspTop10;
private List<String> sansTop25;
private List<String> cwe;


@CheckForNull @CheckForNull
public List<String> getActionPlans() { public List<String> getActionPlans() {
return this; return this;
} }


@CheckForNull
public List<String> getOwaspTop10() {
return owaspTop10;
}

public SearchRequest setOwaspTop10(@Nullable List<String> owaspTop10) {
this.owaspTop10 = owaspTop10;
return this;
}

@CheckForNull
public List<String> getSansTop25() {
return sansTop25;
}

public SearchRequest setSansTop25(@Nullable List<String> sansTop25) {
this.sansTop25 = sansTop25;
return this;
}

@CheckForNull
public List<String> getCwe() {
return cwe;
}

public SearchRequest setCwe(@Nullable List<String> cwe) {
this.cwe = cwe;
return this;
}

@CheckForNull @CheckForNull
public List<String> getComponentRootUuids() { public List<String> getComponentRootUuids() {
return componentRootUuids; return componentRootUuids;

+ 30
- 0
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueDoc.java View File

return this; return this;
} }


@CheckForNull
public Collection<String> getOwaspTop10() {
return getNullableField(IssueIndexDefinition.FIELD_ISSUE_OWASP_TOP_10);
}

public IssueDoc setOwaspTop10(@Nullable Collection<String> o) {
setField(IssueIndexDefinition.FIELD_ISSUE_OWASP_TOP_10, o);
return this;
}

@CheckForNull
public Collection<String> getSansTop25() {
return getNullableField(IssueIndexDefinition.FIELD_ISSUE_SANS_TOP_25);
}

public IssueDoc setSansTop25(@Nullable Collection<String> s) {
setField(IssueIndexDefinition.FIELD_ISSUE_SANS_TOP_25, s);
return this;
}

@CheckForNull
public Collection<String> getCwe() {
return getNullableField(IssueIndexDefinition.FIELD_ISSUE_CWE);
}

public IssueDoc setCwe(@Nullable Collection<String> c) {
setField(IssueIndexDefinition.FIELD_ISSUE_CWE, c);
return this;
}

} }

+ 15
- 0
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndex.java View File

import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ASSIGNEES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHORS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_AUTHORS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CWE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_LANGUAGES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_UUIDS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_REPORTERS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_REPORTERS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS;
PARAM_LANGUAGES, PARAM_LANGUAGES,
PARAM_TAGS, PARAM_TAGS,
PARAM_TYPES, PARAM_TYPES,
PARAM_OWASP_TOP_10,
PARAM_SANS_TOP_25,
PARAM_CWE,
PARAM_CREATED_AT); PARAM_CREATED_AT);
public static final String AGGREGATION_NAME_FOR_TAGS = "tags__issues"; public static final String AGGREGATION_NAME_FOR_TAGS = "tags__issues";
private static final String SUBSTRING_MATCH_REGEXP = ".*%s.*"; private static final String SUBSTRING_MATCH_REGEXP = ".*%s.*";
if (options.getFacets().contains(PARAM_TYPES)) { if (options.getFacets().contains(PARAM_TYPES)) {
esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TYPE, PARAM_TYPES, query.types().toArray())); esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TYPE, PARAM_TYPES, query.types().toArray()));
} }
if (options.getFacets().contains(PARAM_OWASP_TOP_10)) {
esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_OWASP_TOP_10, PARAM_OWASP_TOP_10, query.owaspTop10().toArray()));
}
if (options.getFacets().contains(PARAM_SANS_TOP_25)) {
esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_SANS_TOP_25, PARAM_SANS_TOP_25, query.sansTop25().toArray()));
}
if (options.getFacets().contains(PARAM_CWE)) {
esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_CWE, PARAM_CWE, query.cwe().toArray()));
}
if (options.getFacets().contains(PARAM_RESOLUTIONS)) { if (options.getFacets().contains(PARAM_RESOLUTIONS)) {
esSearch.addAggregation(createResolutionFacet(query, filters, esQuery)); esSearch.addAggregation(createResolutionFacet(query, filters, esQuery));
} }

+ 6
- 0
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java View File

public static final String FIELD_ISSUE_STATUS = "status"; public static final String FIELD_ISSUE_STATUS = "status";
public static final String FIELD_ISSUE_TAGS = "tags"; public static final String FIELD_ISSUE_TAGS = "tags";
public static final String FIELD_ISSUE_TYPE = "type"; public static final String FIELD_ISSUE_TYPE = "type";
public static final String FIELD_ISSUE_OWASP_TOP_10 = "owaspTop10";
public static final String FIELD_ISSUE_SANS_TOP_25 = "sansTop25";
public static final String FIELD_ISSUE_CWE = "cwe";


private final Configuration config; private final Configuration config;
private final boolean enableSource; private final boolean enableSource;
type.keywordFieldBuilder(FIELD_ISSUE_STATUS).disableNorms().addSubFields(SORTABLE_ANALYZER).build(); type.keywordFieldBuilder(FIELD_ISSUE_STATUS).disableNorms().addSubFields(SORTABLE_ANALYZER).build();
type.keywordFieldBuilder(FIELD_ISSUE_TAGS).disableNorms().build(); type.keywordFieldBuilder(FIELD_ISSUE_TAGS).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_TYPE).disableNorms().build(); type.keywordFieldBuilder(FIELD_ISSUE_TYPE).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_OWASP_TOP_10).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_SANS_TOP_25).disableNorms().build();
type.keywordFieldBuilder(FIELD_ISSUE_CWE).disableNorms().build();
} }
} }

+ 44
- 4
server/sonar-server-common/src/main/java/org/sonar/server/issue/index/IssueIteratorForSingleChunk.java View File



import com.google.common.base.CharMatcher; import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators; import com.google.common.collect.Iterators;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import org.sonar.db.ResultSetIterator; import org.sonar.db.ResultSetIterator;


import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.sonar.api.utils.DateUtils.longToDate; import static org.sonar.api.utils.DateUtils.longToDate;
import static org.sonar.db.DatabaseUtils.getLong; import static org.sonar.db.DatabaseUtils.getLong;
import static org.sonar.server.issue.ws.SearchAction.SANS_TOP_25_INSECURE_INTERACTION;
import static org.sonar.server.issue.ws.SearchAction.SANS_TOP_25_POROUS_DEFENSES;
import static org.sonar.server.issue.ws.SearchAction.SANS_TOP_25_RISKY_RESOURCE;
import static org.sonar.server.issue.ws.SearchAction.UNKNOWN_STANDARD;


/** /**
* Scrolls over table ISSUES and reads documents to populate * Scrolls over table ISSUES and reads documents to populate
"c.scope", "c.scope",
"c.organization_uuid", "c.organization_uuid",
"c.project_uuid", "c.project_uuid",
"c.main_branch_project_uuid",


// column 21 // column 21
"c.main_branch_project_uuid",
"i.tags", "i.tags",
"i.issue_type"
"i.issue_type",
"r.security_standards"
}; };


private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from issues i " + private static final String SQL_ALL = "select " + StringUtils.join(FIELDS, ",") + " from issues i " +
private static final String ISSUE_KEY_FILTER_SUFFIX = ")"; private static final String ISSUE_KEY_FILTER_SUFFIX = ")";


static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings(); static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
static final Splitter SECURITY_STANDARDS_SPLITTER = TAGS_SPLITTER;
static final Splitter MODULE_PATH_SPLITTER = Splitter.on('.').trimResults().omitEmptyStrings(); static final Splitter MODULE_PATH_SPLITTER = Splitter.on('.').trimResults().omitEmptyStrings();
private static final String OWASP_TOP10_PREFIX = "owaspTop10:";
private static final String CWE_PREFIX = "cwe:";

// See https://www.sans.org/top25-software-errors
private static final Set<String> INSECURE_CWE = new HashSet<>(asList("89", "78", "79", "434", "352", "601"));
private static final Set<String> RISKY_CWE = new HashSet<>(asList("120", "22", "494", "829", "676", "131", "134", "190"));
private static final Set<String> POROUS_CWE = new HashSet<>(asList("306", "862", "798", "311", "807", "250", "863", "732", "327", "307", "759"));
private static final Map<String, Set<String>> SANS_TOP_25_CWE_MAPPING = ImmutableMap.of(
SANS_TOP_25_INSECURE_INTERACTION, INSECURE_CWE,
SANS_TOP_25_RISKY_RESOURCE, RISKY_CWE,
SANS_TOP_25_POROUS_DEFENSES, POROUS_CWE);


private final DbSession session; private final DbSession session;


doc.setIsMainBranch(false); doc.setIsMainBranch(false);
} }
String tags = rs.getString(21); String tags = rs.getString(21);
doc.setTags(ImmutableList.copyOf(IssueIteratorForSingleChunk.TAGS_SPLITTER.split(tags == null ? "" : tags)));
doc.setTags(IssueIteratorForSingleChunk.TAGS_SPLITTER.splitToList(tags == null ? "" : tags));
doc.setType(RuleType.valueOf(rs.getInt(22))); doc.setType(RuleType.valueOf(rs.getInt(22)));
String securityStandards = rs.getString(23);

List<String> standards = IssueIteratorForSingleChunk.SECURITY_STANDARDS_SPLITTER.splitToList(securityStandards == null ? "" : securityStandards);
List<String> owaspTop10 = standards.stream().filter(s -> s.startsWith(OWASP_TOP10_PREFIX)).map(s -> s.substring(OWASP_TOP10_PREFIX.length())).collect(toList());
doc.setOwaspTop10(owaspTop10.isEmpty() ? Collections.singletonList(UNKNOWN_STANDARD) : owaspTop10);
List<String> cwe = standards.stream().filter(s -> s.startsWith(CWE_PREFIX)).map(s -> s.substring(CWE_PREFIX.length())).collect(toList());
doc.setCwe(cwe.isEmpty() ? Collections.singletonList(UNKNOWN_STANDARD) : cwe);
doc.setSansTop25(getSansTop25(cwe));
return doc; return doc;
} }


private static List<String> getSansTop25(List<String> cwe) {
return SANS_TOP_25_CWE_MAPPING
.keySet()
.stream()
.filter(k -> cwe.stream().anyMatch(SANS_TOP_25_CWE_MAPPING.get(k)::contains))
.collect(toList());
}

@CheckForNull @CheckForNull
private static String extractDirPath(@Nullable String filePath, String scope) { private static String extractDirPath(@Nullable String filePath, String scope) {
if (filePath != null) { if (filePath != null) {

+ 12
- 0
server/sonar-server-common/src/test/java/org/sonar/server/issue/IssueQueryTest.java View File

.languages(newArrayList("xoo")) .languages(newArrayList("xoo"))
.tags(newArrayList("tag1", "tag2")) .tags(newArrayList("tag1", "tag2"))
.types(newArrayList("RELIABILITY", "SECURITY")) .types(newArrayList("RELIABILITY", "SECURITY"))
.owaspTop10(newArrayList("a1", "a2"))
.sansTop25(newArrayList("insecure-interaction", "porous-defenses"))
.cwe(newArrayList("12", "125"))
.organizationUuid("orga") .organizationUuid("orga")
.branchUuid("my_branch") .branchUuid("my_branch")
.createdAfterByProjectUuids(ImmutableMap.of("PROJECT", filterDate)) .createdAfterByProjectUuids(ImmutableMap.of("PROJECT", filterDate))
assertThat(query.languages()).containsOnly("xoo"); assertThat(query.languages()).containsOnly("xoo");
assertThat(query.tags()).containsOnly("tag1", "tag2"); assertThat(query.tags()).containsOnly("tag1", "tag2");
assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY"); assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY");
assertThat(query.owaspTop10()).containsOnly("a1", "a2");
assertThat(query.sansTop25()).containsOnly("insecure-interaction", "porous-defenses");
assertThat(query.cwe()).containsOnly("12", "125");
assertThat(query.organizationUuid()).isEqualTo("orga"); assertThat(query.organizationUuid()).isEqualTo("orga");
assertThat(query.branchUuid()).isEqualTo("my_branch"); assertThat(query.branchUuid()).isEqualTo("my_branch");
assertThat(query.createdAfterByProjectUuids()).containsOnly(entry("PROJECT", filterDate)); assertThat(query.createdAfterByProjectUuids()).containsOnly(entry("PROJECT", filterDate));
.languages(null) .languages(null)
.tags(null) .tags(null)
.types(null) .types(null)
.owaspTop10(null)
.sansTop25(null)
.cwe(null)
.createdAfterByProjectUuids(null) .createdAfterByProjectUuids(null)
.build(); .build();
assertThat(query.issueKeys()).isEmpty(); assertThat(query.issueKeys()).isEmpty();
assertThat(query.languages()).isEmpty(); assertThat(query.languages()).isEmpty();
assertThat(query.tags()).isEmpty(); assertThat(query.tags()).isEmpty();
assertThat(query.types()).isEmpty(); assertThat(query.types()).isEmpty();
assertThat(query.owaspTop10()).isEmpty();
assertThat(query.sansTop25()).isEmpty();
assertThat(query.cwe()).isEmpty();
assertThat(query.createdAfterByProjectUuids()).isEmpty(); assertThat(query.createdAfterByProjectUuids()).isEmpty();
} }



+ 22
- 0
server/sonar-server-common/src/test/java/org/sonar/server/issue/index/IssueIndexerTest.java View File

import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.sonar.db.component.ComponentTesting.newFileDto; import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.server.issue.IssueDocTesting.newDoc; import static org.sonar.server.issue.IssueDocTesting.newDoc;
import static org.sonar.server.issue.index.IssueIndexDefinition.INDEX_TYPE_ISSUE; import static org.sonar.server.issue.index.IssueIndexDefinition.INDEX_TYPE_ISSUE;
import static org.sonar.server.issue.ws.SearchAction.SANS_TOP_25_POROUS_DEFENSES;
import static org.sonar.server.issue.ws.SearchAction.UNKNOWN_STANDARD;
import static org.sonar.server.permission.index.AuthorizationTypeSupport.TYPE_AUTHORIZATION; import static org.sonar.server.permission.index.AuthorizationTypeSupport.TYPE_AUTHORIZATION;


public class IssueIndexerTest { public class IssueIndexerTest {
assertThat(doc.line()).isEqualTo(issue.getLine()); assertThat(doc.line()).isEqualTo(issue.getLine());
// functional date // functional date
assertThat(doc.updateDate()).isEqualToIgnoringMillis(new Date(issue.getIssueUpdateTime())); assertThat(doc.updateDate()).isEqualToIgnoringMillis(new Date(issue.getIssueUpdateTime()));
assertThat(doc.getCwe()).containsExactlyInAnyOrder(UNKNOWN_STANDARD);
assertThat(doc.getOwaspTop10()).containsExactlyInAnyOrder(UNKNOWN_STANDARD);
assertThat(doc.getSansTop25()).isEmpty();
}

@Test
public void verify_security_standards_indexation() {
RuleDefinitionDto rule = db.rules().insert(r -> r.setSecurityStandards(new HashSet<>(Arrays.asList("cwe:123,owaspTop10:a3,cwe:863"))));
ComponentDto project = db.components().insertPrivateProject(organization);
ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
ComponentDto file = db.components().insertComponent(newFileDto(project, dir, "F1"));
IssueDto issue = db.issues().insertIssue(IssueTesting.newIssue(rule, project, file));

underTest.indexOnStartup(emptySet());

IssueDoc doc = es.getDocuments(INDEX_TYPE_ISSUE, IssueDoc.class).get(0);
assertThat(doc.getCwe()).containsExactlyInAnyOrder("123", "863");
assertThat(doc.getOwaspTop10()).containsExactlyInAnyOrder("a3");
assertThat(doc.getSansTop25()).containsExactlyInAnyOrder(SANS_TOP_25_POROUS_DEFENSES);
} }


@Test @Test

+ 27
- 2
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java View File

import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AT;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_BEFORE; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_BEFORE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_LAST; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_LAST;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CWE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_DIRECTORIES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_FILE_UUIDS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_MODULE_UUIDS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ON_COMPONENT_ONLY; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ON_COMPONENT_ONLY;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ORGANIZATION;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_OWASP_TOP_10;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PLANNED; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PLANNED;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLUTIONS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLVED; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RESOLVED;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_RULES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SANS_TOP_25;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITIES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES;
public class SearchAction implements IssuesWsAction { public class SearchAction implements IssuesWsAction {


public static final String LOGIN_MYSELF = "__me__"; public static final String LOGIN_MYSELF = "__me__";
public static final String UNKNOWN_STANDARD = "unknown";
public static final String SANS_TOP_25_INSECURE_INTERACTION = "insecure-interaction";
public static final String SANS_TOP_25_RISKY_RESOURCE = "risky-resource";
public static final String SANS_TOP_25_POROUS_DEFENSES = "porous-defenses";


private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. "; private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. ";
private static final Set<String> IGNORED_FACETS = newHashSet(PARAM_PLANNED, DEPRECATED_PARAM_ACTION_PLANS, PARAM_REPORTERS); private static final Set<String> IGNORED_FACETS = newHashSet(PARAM_PLANNED, DEPRECATED_PARAM_ACTION_PLANS, PARAM_REPORTERS);
new Change("5.5", "response field 'debt' is renamed 'effort'"), new Change("5.5", "response field 'debt' is renamed 'effort'"),
new Change("7.2", "response field 'externalRuleEngine' added to issues that have been imported from an external rule engine"), new Change("7.2", "response field 'externalRuleEngine' added to issues that have been imported from an external rule engine"),
new Change("7.2", format("value '%s' in parameter '%s' is deprecated, it won't have any effect", SORT_BY_ASSIGNEE, Param.SORT)), new Change("7.2", format("value '%s' in parameter '%s' is deprecated, it won't have any effect", SORT_BY_ASSIGNEE, Param.SORT)),
new Change("7.3", "response field 'fromHotspot' added to issues that are security hotspots"))
new Change("7.3", "response field 'fromHotspot' added to issues that are security hotspots"),
new Change("7.3", "added facets 'sansTop25', 'owaspTop10' and 'cwe'"))
.setResponseExample(getClass().getResource("search-example.json")); .setResponseExample(getClass().getResource("search-example.json"));


action.addPagingParams(100, MAX_LIMIT); action.addPagingParams(100, MAX_LIMIT);
.setSince("5.5") .setSince("5.5")
.setPossibleValues((Object[]) RuleType.values()) .setPossibleValues((Object[]) RuleType.values())
.setExampleValue(format("%s,%s", RuleType.CODE_SMELL, RuleType.BUG)); .setExampleValue(format("%s,%s", RuleType.CODE_SMELL, RuleType.BUG));
action.createParam(PARAM_OWASP_TOP_10)
.setDescription("Comma-separated list of OWASP Top 10 lowercase categories. Use '" + UNKNOWN_STANDARD + "' to select issues not associated to any OWASP Top 10 category.")
.setSince("7.3")
.setPossibleValues("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "a10", UNKNOWN_STANDARD);
action.createParam(PARAM_SANS_TOP_25)
.setDescription("Comma-separated list of SANS Top 25 categories.")
.setSince("7.3")
.setPossibleValues(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES);
action.createParam(PARAM_CWE)
.setDescription("Comma-separated list of CWE identifiers. Use '" + UNKNOWN_STANDARD + "' to select issues not associated to any CWE.")
.setExampleValue("12,125," + UNKNOWN_STANDARD);
action.createParam(PARAM_AUTHORS) action.createParam(PARAM_AUTHORS)
.setDescription("Comma-separated list of SCM accounts") .setDescription("Comma-separated list of SCM accounts")
.setExampleValue("torvalds@linux-foundation.org"); .setExampleValue("torvalds@linux-foundation.org");
addMandatoryValuesToFacet(facets, PARAM_LANGUAGES, request.getLanguages()); addMandatoryValuesToFacet(facets, PARAM_LANGUAGES, request.getLanguages());
addMandatoryValuesToFacet(facets, PARAM_TAGS, request.getTags()); addMandatoryValuesToFacet(facets, PARAM_TAGS, request.getTags());
addMandatoryValuesToFacet(facets, PARAM_TYPES, RuleType.names()); addMandatoryValuesToFacet(facets, PARAM_TYPES, RuleType.names());
addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10, request.getOwaspTop10());
addMandatoryValuesToFacet(facets, PARAM_SANS_TOP_25, request.getSansTop25());
addMandatoryValuesToFacet(facets, PARAM_CWE, request.getCwe());
addMandatoryValuesToFacet(facets, PARAM_COMPONENT_UUIDS, request.getComponentUuids()); addMandatoryValuesToFacet(facets, PARAM_COMPONENT_UUIDS, request.getComponentUuids());


List<String> requestedFacets = request.getFacets(); List<String> requestedFacets = request.getFacets();
.setSeverities(request.paramAsStrings(PARAM_SEVERITIES)) .setSeverities(request.paramAsStrings(PARAM_SEVERITIES))
.setStatuses(request.paramAsStrings(PARAM_STATUSES)) .setStatuses(request.paramAsStrings(PARAM_STATUSES))
.setTags(request.paramAsStrings(PARAM_TAGS)) .setTags(request.paramAsStrings(PARAM_TAGS))
.setTypes(request.paramAsStrings(PARAM_TYPES));
.setTypes(request.paramAsStrings(PARAM_TYPES))
.setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
.setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
.setCwe(request.paramAsStrings(PARAM_CWE));
} }
} }

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java View File

"pullRequest", "organization", "pullRequest", "organization",
"createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly", "createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly",
"p", "projectUuids", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "p", "projectUuids", "projects", "ps", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod",
"statuses", "tags", "types");
"statuses", "tags", "types", "owaspTop10", "sansTop25", "cwe");


assertThat(def.param("organization")) assertThat(def.param("organization"))
.matches(WebService.Param::isInternal) .matches(WebService.Param::isInternal)

+ 4
- 1
sonar-ws/src/main/java/org/sonarqube/ws/client/issue/IssuesWsParameters.java View File

public static final String PARAM_LANGUAGES = "languages"; public static final String PARAM_LANGUAGES = "languages";
public static final String PARAM_TAGS = "tags"; public static final String PARAM_TAGS = "tags";
public static final String PARAM_TYPES = "types"; public static final String PARAM_TYPES = "types";
public static final String PARAM_OWASP_TOP_10 = "owaspTop10";
public static final String PARAM_SANS_TOP_25 = "sansTop25";
public static final String PARAM_CWE = "cwe";
public static final String PARAM_ASSIGNED = "assigned"; public static final String PARAM_ASSIGNED = "assigned";


/** /**
public static final String FACET_ASSIGNED_TO_ME = "assigned_to_me"; public static final String FACET_ASSIGNED_TO_ME = "assigned_to_me";


public static final List<String> ALL = ImmutableList.of(PARAM_ISSUES, PARAM_SEVERITIES, PARAM_STATUSES, PARAM_RESOLUTIONS, PARAM_RESOLVED, public static final List<String> ALL = ImmutableList.of(PARAM_ISSUES, PARAM_SEVERITIES, PARAM_STATUSES, PARAM_RESOLUTIONS, PARAM_RESOLVED,
PARAM_COMPONENTS, PARAM_COMPONENT_ROOTS, PARAM_RULES, DEPRECATED_PARAM_ACTION_PLANS, PARAM_REPORTERS, PARAM_TAGS, PARAM_TYPES,
PARAM_COMPONENTS, PARAM_COMPONENT_ROOTS, PARAM_RULES, DEPRECATED_PARAM_ACTION_PLANS, PARAM_REPORTERS, PARAM_TAGS, PARAM_TYPES, PARAM_OWASP_TOP_10, PARAM_SANS_TOP_25, PARAM_CWE,
PARAM_ASSIGNEES, PARAM_LANGUAGES, PARAM_ASSIGNED, PARAM_PLANNED, PARAM_HIDE_RULES, PARAM_CREATED_AT, PARAM_CREATED_AFTER, PARAM_CREATED_BEFORE, PARAM_CREATED_IN_LAST, PARAM_ASSIGNEES, PARAM_LANGUAGES, PARAM_ASSIGNED, PARAM_PLANNED, PARAM_HIDE_RULES, PARAM_CREATED_AT, PARAM_CREATED_AFTER, PARAM_CREATED_BEFORE, PARAM_CREATED_IN_LAST,
PARAM_COMPONENT_UUIDS, PARAM_COMPONENT_ROOT_UUIDS, FACET_MODE, PARAM_COMPONENT_UUIDS, PARAM_COMPONENT_ROOT_UUIDS, FACET_MODE,
PARAM_PROJECTS, PARAM_PROJECT_UUIDS, PARAM_PROJECT_KEYS, PARAM_COMPONENT_KEYS, PARAM_MODULE_UUIDS, PARAM_DIRECTORIES, PARAM_FILE_UUIDS, PARAM_AUTHORS, PARAM_PROJECTS, PARAM_PROJECT_UUIDS, PARAM_PROJECT_KEYS, PARAM_COMPONENT_KEYS, PARAM_MODULE_UUIDS, PARAM_DIRECTORIES, PARAM_FILE_UUIDS, PARAM_AUTHORS,

Loading…
Cancel
Save