Browse Source

SONAR-10867 Add security hotspot new issue type

tags/7.5
Julien HENRY 6 years ago
parent
commit
d42307dd48
20 changed files with 109 additions and 33 deletions
  1. 3
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java
  2. 3
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java
  3. 2
    0
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java
  4. 19
    19
      server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java
  5. 1
    1
      server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java
  6. 2
    1
      server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java
  7. 4
    0
      server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json
  8. 1
    1
      server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx
  9. 1
    1
      server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx
  10. 1
    1
      server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
  11. 5
    3
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx
  12. 9
    1
      server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap
  13. 43
    0
      server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx
  14. 5
    0
      server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx
  15. 1
    1
      server/sonar-web/src/main/js/helpers/constants.ts
  16. 3
    0
      sonar-core/src/main/resources/org/sonar/l10n/core.properties
  17. 1
    1
      sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java
  18. 3
    3
      sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java
  19. 1
    0
      sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
  20. 1
    0
      sonar-ws/src/main/protobuf/ws-commons.proto

+ 3
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/EffortAggregator.java View File

case VULNERABILITY: case VULNERABILITY:
securityEffort += issueEffort; securityEffort += issueEffort;
break; break;
case SECURITY_HOTSPOT:
// Not counted
break;
default: default:
throw new IllegalStateException(String.format("Unknown type '%s'", issue.type())); throw new IllegalStateException(String.format("Unknown type '%s'", issue.type()));
} }

+ 3
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/NewEffortAggregator.java View File

case VULNERABILITY: case VULNERABILITY:
securitySum.add(newEffort); securitySum.add(newEffort);
break; break;
case SECURITY_HOTSPOT:
// Not counted
break;
default: default:
throw new IllegalStateException(String.format("Unknown type '%s'", issue.type())); throw new IllegalStateException(String.format("Unknown type '%s'", issue.type()));
} }

+ 2
- 0
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactory.java View File

return RuleType.CODE_SMELL; return RuleType.CODE_SMELL;
case VULNERABILITY: case VULNERABILITY:
return RuleType.VULNERABILITY; return RuleType.VULNERABILITY;
case SECURITY_HOTSPOT:
return RuleType.SECURITY_HOTSPOT;
case UNRECOGNIZED: case UNRECOGNIZED:
default: default:
throw new IllegalStateException("Invalid issue type: " + type); throw new IllegalStateException("Invalid issue type: " + type);

+ 19
- 19
server/sonar-server/src/test/java/org/sonar/server/issue/notification/NewIssuesStatisticsTest.java View File

public ExpectedException expectedException = ExpectedException.none(); public ExpectedException expectedException = ExpectedException.none();


private final Random random = new Random(); private final Random random = new Random();
private RuleType randomRuleType = RuleType.values()[random.nextInt(RuleType.values().length)];
private RuleType randomRuleTypeExceptHotspot = RuleType.values()[random.nextInt(RuleType.values().length - 1)];
private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew); private NewIssuesStatistics underTest = new NewIssuesStatistics(Issue::isNew);


@Test @Test
List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
componentUuids.stream() componentUuids.stream()
.map(componentUuid -> new DefaultIssue().setType(randomRuleType).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true))
.map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> componentUuids = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
componentUuids.stream() componentUuids.stream()
.map(componentUuid -> new DefaultIssue().setType(randomRuleType).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false))
.map(componentUuid -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(componentUuid).setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
@Test @Test
public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() { public void add_does_not_count_component_if_null_neither_globally_nor_per_assignee() {
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setComponentUuid(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.COMPONENT);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.COMPONENT);
List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
ruleKeys.stream() ruleKeys.stream()
.map(ruleKey -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true))
.map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> ruleKeys = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
ruleKeys.stream() ruleKeys.stream()
.map(ruleKey -> new DefaultIssue().setType(randomRuleType).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false))
.map(ruleKey -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(RuleKey.of(repository, ruleKey)).setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
@Test @Test
public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() { public void add_does_not_count_ruleKey_if_null_neither_globally_nor_per_assignee() {
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setRuleKey(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.RULE);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.RULE);
public void add_counts_issue_per_assignee_on_leak_globally_and_per_assignee() { public void add_counts_issue_per_assignee_on_leak_globally_and_per_assignee() {
List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
assignees.stream() assignees.stream()
.map(assignee -> new DefaultIssue().setType(randomRuleType).setAssigneeUuid(assignee).setNew(true))
.map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
public void add_counts_issue_per_assignee_off_leak_globally_and_per_assignee() { public void add_counts_issue_per_assignee_off_leak_globally_and_per_assignee() {
List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> assignees = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
assignees.stream() assignees.stream()
.map(assignee -> new DefaultIssue().setType(randomRuleType).setAssigneeUuid(assignee).setNew(false))
.map(assignee -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add); .forEach(underTest::add);


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);


@Test @Test
public void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() { public void add_does_not_assignee_if_empty_neither_globally_nor_per_assignee() {
underTest.add(new DefaultIssue().setType(randomRuleType).setAssigneeUuid(null).setNew(new Random().nextBoolean()));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setAssigneeUuid(null).setNew(new Random().nextBoolean()));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.ASSIGNEE);
assertThat(globalDistribution.getTotal()).isEqualTo(0); assertThat(globalDistribution.getTotal()).isEqualTo(0);
public void add_counts_issue_per_tags_on_leak_globally_and_per_assignee() { public void add_counts_issue_per_tags_on_leak_globally_and_per_assignee() {
List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setTags(tags).setAssigneeUuid(assignee).setNew(true));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(true));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
public void add_counts_issue_per_tags_off_leak_globally_and_per_assignee() { public void add_counts_issue_per_tags_off_leak_globally_and_per_assignee() {
List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList()); List<String> tags = IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> randomAlphabetic(3)).collect(Collectors.toList());
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setTags(tags).setAssigneeUuid(assignee).setNew(false));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(tags).setAssigneeUuid(assignee).setNew(false));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
@Test @Test
public void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() { public void add_does_not_count_tags_if_empty_neither_globally_nor_per_assignee() {
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setTags(Collections.emptyList()).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));


DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt globalDistribution = underTest.globalStatistics().getDistributedMetricStats(Metric.TAG);
DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG); DistributedMetricStatsInt assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).getDistributedMetricStats(Metric.TAG);
int expected = efforts.stream().mapToInt(s -> s).sum(); int expected = efforts.stream().mapToInt(s -> s).sum();
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
efforts.stream() efforts.stream()
.map(effort -> new DefaultIssue().setType(randomRuleType).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true))
.map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(true))
.forEach(underTest::add); .forEach(underTest::add);


MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
int expected = efforts.stream().mapToInt(s -> s).sum(); int expected = efforts.stream().mapToInt(s -> s).sum();
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
efforts.stream() efforts.stream()
.map(effort -> new DefaultIssue().setType(randomRuleType).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false))
.map(effort -> new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(Duration.create(effort)).setAssigneeUuid(assignee).setNew(false))
.forEach(underTest::add); .forEach(underTest::add);


MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
@Test @Test
public void add_does_not_sum_effort_if_null_neither_globally_nor_per_assignee() { public void add_does_not_sum_effort_if_null_neither_globally_nor_per_assignee() {
String assignee = randomAlphanumeric(10); String assignee = randomAlphanumeric(10);
underTest.add(new DefaultIssue().setType(randomRuleType).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));
underTest.add(new DefaultIssue().setType(randomRuleTypeExceptHotspot).setEffort(null).setAssigneeUuid(assignee).setNew(new Random().nextBoolean()));


MetricStatsLong globalDistribution = underTest.globalStatistics().effort(); MetricStatsLong globalDistribution = underTest.globalStatistics().effort();
MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort(); MetricStatsLong assigneeDistribution = underTest.getAssigneesStatistics().get(assignee).effort();
int effort = 10 + new Random().nextInt(5); int effort = 10 + new Random().nextInt(5);
RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6)); RuleKey ruleKey = RuleKey.of(randomAlphanumeric(5), randomAlphanumeric(6));
underTest.add(new DefaultIssue() underTest.add(new DefaultIssue()
.setType(randomRuleType)
.setType(randomRuleTypeExceptHotspot)
.setComponentUuid(componentUuid) .setComponentUuid(componentUuid)
.setTags(ImmutableSet.of(tag)) .setTags(ImmutableSet.of(tag))
.setAssigneeUuid(assignee) .setAssigneeUuid(assignee)
"assigneesStatistics={" + assignee + "=" + "assigneesStatistics={" + assignee + "=" +
"Stats{distributions={" + "Stats{distributions={" +
"RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +
"statsPerLabel={" + randomRuleType.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +
"statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +
"effortStats=MetricStatsLong{onLeak=" + effort + ", offLeak=0}}}, " + "effortStats=MetricStatsLong{onLeak=" + effort + ", offLeak=0}}}, " +
"globalStatistics=Stats{distributions={" + "globalStatistics=Stats{distributions={" +
"RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "RULE_TYPE=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +
"statsPerLabel={" + randomRuleType.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"statsPerLabel={" + randomRuleTypeExceptHotspot.name() + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "TAG=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +
"statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " + "statsPerLabel={" + tag + "=MetricStatsInt{onLeak=1, offLeak=0}}}, " +
"COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " + "COMPONENT=DistributedMetricStatsInt{globalStats=MetricStatsInt{onLeak=1, offLeak=0}, " +

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

setUserWithBrowseAndAdministerIssuePermission(issueDto); setUserWithBrowseAndAdministerIssuePermission(issueDto);


expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Value of parameter 'type' (unknown) must be one of: [CODE_SMELL, BUG, VULNERABILITY]");
expectedException.expectMessage("Value of parameter 'type' (unknown) must be one of: [CODE_SMELL, BUG, VULNERABILITY, SECURITY_HOTSPOT]");
call(issueDto.getKey(), "unknown"); call(issueDto.getKey(), "unknown");
} }



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

.containsExactlyInAnyOrder( .containsExactlyInAnyOrder(
tuple("BUG" /* rule2 */, 0L), tuple("BUG" /* rule2 */, 0L),
tuple("CODE_SMELL"/* rule1 */, 1L), tuple("CODE_SMELL"/* rule1 */, 1L),
tuple("VULNERABILITY", 0L));
tuple("VULNERABILITY", 0L),
tuple("SECURITY_HOTSPOT", 0L));
} }


@Test @Test

+ 4
- 0
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionTest/display_facets.json View File

{ {
"val": "VULNERABILITY", "val": "VULNERABILITY",
"count": 0 "count": 0
},
{
"val": "SECURITY_HOTSPOT",
"count": 0
} }
] ]
} }

+ 1
- 1
server/sonar-web/src/main/js/apps/coding-rules/components/TypeFacet.tsx View File

renderTextName = (type: string) => translate('issue.type', type); renderTextName = (type: string) => translate('issue.type', type);


render() { render() {
const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
const options = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];


return ( return (
<Facet <Facet

+ 1
- 1
server/sonar-web/src/main/js/apps/issues/sidebar/TypeFacet.tsx View File

}; };


render() { render() {
const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];
const values = this.props.types.map(type => translate('issue.type', type)); const values = this.props.types.map(type => translate('issue.type', type));


return ( return (

+ 1
- 1
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx View File

import { translate } from '../../../helpers/l10n'; import { translate } from '../../../helpers/l10n';
import { Profile } from '../types'; import { Profile } from '../types';


const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];


interface Props { interface Props {
organization: string | null; organization: string | null;

+ 5
- 3
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx View File

const EDITABLE_PROFILE = { ...PROFILE, actions: { edit: true } }; const EDITABLE_PROFILE = { ...PROFILE, actions: { edit: true } };


const apiResponseAll = { const apiResponseAll = {
total: 243,
total: 253,
facets: [ facets: [
{ {
property: 'types', property: 'types',
values: [ values: [
{ val: 'CODE_SMELL', count: 168 }, { val: 'CODE_SMELL', count: 168 },
{ val: 'BUG', count: 68 }, { val: 'BUG', count: 68 },
{ val: 'VULNERABILITY', count: 7 }
{ val: 'VULNERABILITY', count: 7 },
{ val: 'SECURITY_HOTSPOT', count: 10 }
] ]
} }
] ]
values: [ values: [
{ val: 'BUG', count: 68 }, { val: 'BUG', count: 68 },
{ val: 'CODE_SMELL', count: 0 }, { val: 'CODE_SMELL', count: 0 },
{ val: 'VULNERABILITY', count: 0 }
{ val: 'VULNERABILITY', count: 0 },
{ val: 'SECURITY_HOTSPOT', count: 0 }
] ]
} }
] ]

+ 9
- 1
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap View File

count={68} count={68}
organization="foo" organization="foo"
qprofile="foo" qprofile="foo"
total={243}
total={253}
/> />
<ProfileRulesRowOfType <ProfileRulesRowOfType
count={68} count={68}
total={168} total={168}
type="CODE_SMELL" type="CODE_SMELL"
/> />
<ProfileRulesRowOfType
count={0}
key="SECURITY_HOTSPOT"
organization="foo"
qprofile="foo"
total={10}
type="SECURITY_HOTSPOT"
/>
</tbody> </tbody>
</table> </table>
</div> </div>

+ 43
- 0
server/sonar-web/src/main/js/components/icons-components/SecurityHotspotIcon.tsx View File

/*
* SonarQube
* Copyright (C) 2009-2018 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.
*/
import * as React from 'react';
import Icon, { IconProps } from './Icon';

export default function SecurityHotspotIcon({ className, fill = 'currentColor', size }: IconProps) {
return (
<Icon className={className} size={size}>
<g style={{ fill }}>
<path
d="M10.238 2.416c-0.432-0.895-1.259-1.504-2.202-1.504-1.386 0-2.521 1.318-2.521 2.927v5.481"
fill="none"
stroke={fill}
strokeLinecap="round"
strokeWidth="1.1429"
/>
<path d="M8.537 10.372v1.199h-1.099v-1.199c-0.638-0.228-1.099-0.832-1.099-1.546 0-0.909 0.739-1.649 1.648-1.649s1.649 0.74 1.649 1.649c0 0.715-0.461 1.32-1.099 1.546zM10.734 4.979h-5.494c-1.21 0-2.199 0.989-2.199 2.197v4.395c0 1.21 0.989 2.199 2.199 2.199h5.494c1.209 0 2.197-0.989 2.197-2.199v-4.395c0-1.209-0.989-2.197-2.197-2.197z" />
<path d="M4.030 6.352h6.923v6.923h-6.923z" />
<path
d="M7.504 10.283c0-0.423 0.048-0.757 0.144-1.002s0.251-0.457 0.465-0.637c0.215-0.18 0.377-0.344 0.489-0.493s0.167-0.313 0.167-0.493c0-0.438-0.189-0.656-0.565-0.656-0.174 0-0.314 0.064-0.421 0.191s-0.164 0.3-0.17 0.518h-1.469c0.006-0.58 0.189-1.031 0.548-1.354s0.864-0.485 1.513-0.485c0.646 0 1.147 0.149 1.501 0.447s0.532 0.723 0.532 1.274c0 0.241-0.048 0.459-0.144 0.656s-0.249 0.398-0.46 0.604l-0.5 0.465c-0.142 0.136-0.241 0.276-0.296 0.42s-0.086 0.325-0.091 0.545h-1.243zM7.326 11.604c0-0.215 0.078-0.39 0.233-0.528s0.349-0.207 0.58-0.207c0.232 0 0.425 0.068 0.58 0.207s0.233 0.313 0.233 0.528-0.078 0.39-0.233 0.528c-0.155 0.138-0.349 0.207-0.58 0.207s-0.425-0.068-0.58-0.207c-0.155-0.138-0.233-0.313-0.233-0.528z"
fill="#fff"
/>
</g>
</Icon>
);
}

+ 5
- 0
server/sonar-web/src/main/js/components/ui/IssueTypeIcon.tsx View File

import BugIcon from '../icons-components/BugIcon'; import BugIcon from '../icons-components/BugIcon';
import VulnerabilityIcon from '../icons-components/VulnerabilityIcon'; import VulnerabilityIcon from '../icons-components/VulnerabilityIcon';
import CodeSmellIcon from '../icons-components/CodeSmellIcon'; import CodeSmellIcon from '../icons-components/CodeSmellIcon';
import SecurityHotspotIcon from '../icons-components/SecurityHotspotIcon';


interface Props { interface Props {
className?: string; className?: string;
case 'new_code_smells': case 'new_code_smells':
icon = <CodeSmellIcon size={size} />; icon = <CodeSmellIcon size={size} />;
break; break;
case 'security_hotspot':
case 'security_hotspots':
icon = <SecurityHotspotIcon size={size} />;
break;
} }


if (!icon) { if (!icon) {

+ 1
- 1
server/sonar-web/src/main/js/helpers/constants.ts View File



export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; export const SEVERITIES = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO'];
export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED']; export const STATUSES = ['OPEN', 'REOPENED', 'CONFIRMED', 'RESOLVED', 'CLOSED'];
export const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
export const TYPES = ['BUG', 'VULNERABILITY', 'CODE_SMELL', 'SECURITY_HOTSPOT'];
export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED']; export const RULE_STATUSES = ['READY', 'BETA', 'DEPRECATED'];


export const CHART_COLORS_RANGE_PERCENT = [ export const CHART_COLORS_RANGE_PERCENT = [

+ 3
- 0
sonar-core/src/main/resources/org/sonar/l10n/core.properties View File

issue.type.CODE_SMELL=Code Smell issue.type.CODE_SMELL=Code Smell
issue.type.BUG=Bug issue.type.BUG=Bug
issue.type.VULNERABILITY=Vulnerability issue.type.VULNERABILITY=Vulnerability
issue.type.SECURITY_HOTSPOT=Security Hotspot
issue.type.CODE_SMELL.plural=Code Smells issue.type.CODE_SMELL.plural=Code Smells
issue.type.BUG.plural=Bugs issue.type.BUG.plural=Bugs
issue.type.VULNERABILITY.plural=Vulnerabilities issue.type.VULNERABILITY.plural=Vulnerabilities
issue.type.SECURITY_HOTSPOT.plural=Security Hotspots




issue.status.REOPENED=Reopened issue.status.REOPENED=Reopened
coding_rules.type.tooltip.CODE_SMELL=Code Smell Detection Rule coding_rules.type.tooltip.CODE_SMELL=Code Smell Detection Rule
coding_rules.type.tooltip.BUG=Bug Detection Rule coding_rules.type.tooltip.BUG=Bug Detection Rule
coding_rules.type.tooltip.VULNERABILITY=Vulnerability Detection Rule coding_rules.type.tooltip.VULNERABILITY=Vulnerability Detection Rule
coding_rules.type.tooltip.SECURITY_HOTSPOT=Security Hotspot Detection Rule
coding_rules.update_custom_rule=Update Custom Rule coding_rules.update_custom_rule=Update Custom Rule
coding_rules.filter_similar_rules=Filter Similar Rules coding_rules.filter_similar_rules=Filter Similar Rules



+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/rules/RuleType.java View File

import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toList;


public enum RuleType { public enum RuleType {
CODE_SMELL(1), BUG(2), VULNERABILITY(3);
CODE_SMELL(1), BUG(2), VULNERABILITY(3), SECURITY_HOTSPOT(4);


private static final Set<String> ALL_NAMES = unmodifiableSet(new LinkedHashSet<>(stream(values()) private static final Set<String> ALL_NAMES = unmodifiableSet(new LinkedHashSet<>(stream(values())
.map(Enum::name) .map(Enum::name)

+ 3
- 3
sonar-plugin-api/src/test/java/org/sonar/api/rules/RuleTypeTest.java View File

@Test @Test
public void valueOf_throws_ISE_if_unsupported_db_constant() { public void valueOf_throws_ISE_if_unsupported_db_constant() {
expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Unsupported type value : 4");
RuleType.valueOf(4);
expectedException.expectMessage("Unsupported type value : 5");
RuleType.valueOf(5);
} }


@Test @Test
public void test_ALL_NAMES() { public void test_ALL_NAMES() {
assertThat(RuleType.names()).containsOnly("BUG", "VULNERABILITY", "CODE_SMELL");
assertThat(RuleType.names()).containsOnly("BUG", "VULNERABILITY", "CODE_SMELL", "SECURITY_HOTSPOT");
} }


@Test @Test

+ 1
- 0
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto View File

CODE_SMELL = 0; CODE_SMELL = 0;
BUG = 1; BUG = 1;
VULNERABILITY = 2; VULNERABILITY = 2;
SECURITY_HOTSPOT = 3;
} }


message IssueLocation { message IssueLocation {

+ 1
- 0
sonar-ws/src/main/protobuf/ws-commons.proto View File

CODE_SMELL = 1; CODE_SMELL = 1;
BUG = 2; BUG = 2;
VULNERABILITY = 3; VULNERABILITY = 3;
SECURITY_HOTSPOT = 4;
} }


enum BranchType { enum BranchType {

Loading…
Cancel
Save