@@ -42,6 +42,7 @@ public class DbVersion81 implements DbVersion { | |||
RenameDaysBeforeDeletingInactiveSLBSetting.class) | |||
.add(3112, "Migrate short and long living branches types to common BRANCH type", MigrateSlbsAndLlbsToCommonType.class) | |||
.add(3113, "Migrate short and long living branches types to common BRANCH type in ce tasks table", | |||
MigrateSlbsAndLlbsToCommonTypeInCeTasks.class); | |||
MigrateSlbsAndLlbsToCommonTypeInCeTasks.class) | |||
.add(3114, "Drop 'In Review' Security Hotspots status ", DropSecurityHotSpotsInReviewStatus.class); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* 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.platform.db.migration.version.v81; | |||
import java.sql.SQLException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
public class DropSecurityHotSpotsInReviewStatus extends DataChange { | |||
private System2 system; | |||
public DropSecurityHotSpotsInReviewStatus(Database db, System2 system) { | |||
super(db); | |||
this.system = system; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select id,kee from issues where status = 'IN_REVIEW'"); | |||
massUpdate.update("update issues set status = 'TO_REVIEW' where id = ? and status = 'IN_REVIEW'"); | |||
massUpdate.update("insert into issue_changes(issue_key, change_type, change_data, created_at, updated_at, issue_change_creation_date) " + | |||
"VALUES(?, 'diff', 'status=IN_REVIEW|TO_REVIEW', ?, ?, ?)"); | |||
massUpdate.execute((row, update, updateIndex) -> { | |||
if (updateIndex == 0) { | |||
update.setLong(1, row.getLong(1)); | |||
} else if (updateIndex == 1) { | |||
long currentTime = system.now(); | |||
update.setString(1, row.getString(2)) | |||
.setLong(2, currentTime) | |||
.setLong(3, currentTime) | |||
.setLong(4, currentTime); | |||
} | |||
return true; | |||
}); | |||
} | |||
} |
@@ -36,7 +36,7 @@ public class DbVersion81Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 14); | |||
verifyMigrationCount(underTest, 15); | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
/* | |||
* 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.platform.db.migration.version.v81; | |||
import java.sql.SQLException; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.function.Function; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.CoreDbTester; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.issue.Issue.STATUSES; | |||
public class DropSecurityHotSpotsInReviewStatusTest { | |||
private final static String ISSUES_TABLE_NAME = "issues"; | |||
private final static int NUMBER_OF_ISSUES_IN_REVIEW = 3; | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(DropSecurityHotSpotsInReviewStatusTest.class, "schema.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private System2 system2 = System2.INSTANCE; | |||
private DataChange underTest = new DropSecurityHotSpotsInReviewStatus(db.database(), system2); | |||
@Test | |||
public void should_change_IN_REVIEW_statuses_only() throws SQLException { | |||
Map<Integer, String> statuses = IntStream.range(0, STATUSES.size()) | |||
.boxed() | |||
.collect(Collectors.toMap(Function.identity(), STATUSES::get)); | |||
statuses.forEach(this::insertIssue); | |||
int startIndex = STATUSES.size(); | |||
int endIndex = startIndex + NUMBER_OF_ISSUES_IN_REVIEW; | |||
IntStream.range(startIndex, endIndex).forEach(value -> insertIssue(value, "IN_REVIEW")); | |||
underTest.execute(); | |||
IntStream.range(startIndex, endIndex).forEach(this::assertIssueChanged); | |||
statuses.forEach(this::assertIssueNotChanged); | |||
// should not fail if executed twice | |||
underTest.execute(); | |||
} | |||
@Test | |||
public void should_not_fail_if_no_issues() throws SQLException { | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("issues")).isEqualTo(0); | |||
} | |||
private void assertIssueChanged(int issueId) { | |||
List<Map<String, Object>> row = db.select(String.format("select status from issues where kee = '%s'", "issue-key-" + issueId)); | |||
assertThat(row).hasSize(1); | |||
assertThat(row.get(0).get("STATUS")) | |||
.isEqualTo("TO_REVIEW"); | |||
List<Map<String, Object>> changelogRows = db.select(String.format("select change_type, change_data, created_at, updated_at, issue_change_creation_date" + | |||
" from issue_changes where issue_key = '%s'", "issue-key-" + issueId)); | |||
assertThat(changelogRows).hasSize(1); | |||
Map<String, Object> changelogRow = changelogRows.get(0); | |||
assertThat(changelogRow.get("CHANGE_TYPE")).isEqualTo("diff"); | |||
assertThat(changelogRow.get("CHANGE_DATA")).isEqualTo("status=IN_REVIEW|TO_REVIEW"); | |||
assertThat(changelogRow.get("CREATED_AT")).isNotNull(); | |||
assertThat(changelogRow.get("UPDATED_AT")).isNotNull(); | |||
assertThat(changelogRow.get("ISSUE_CHANGE_CREATION_DATE")).isNotNull(); | |||
} | |||
private void assertIssueNotChanged(int issueId, String expectedStatus) { | |||
List<Map<String, Object>> row = db.select(String.format("select status from issues where kee = '%s'", "issue-key-" + issueId)); | |||
assertThat(row).hasSize(1); | |||
assertThat(row.get(0).get("STATUS")) | |||
.isEqualTo(expectedStatus); | |||
List<Map<String, Object>> changelogRows = db.select(String.format("select change_type, change_data, created_at, updated_at, issue_change_creation_date" + | |||
" from issue_changes where issue_key = '%s'", "issue-key-" + issueId)); | |||
assertThat(changelogRows).isEmpty(); | |||
} | |||
private void insertIssue(int issueId, String status) { | |||
db.executeInsert(ISSUES_TABLE_NAME, | |||
"kee", "issue-key-" + issueId, | |||
"status", status, | |||
"manual_severity", false); | |||
} | |||
} |
@@ -0,0 +1,54 @@ | |||
CREATE TABLE "ISSUES"( | |||
"ID" BIGINT NOT NULL AUTO_INCREMENT (1,1), | |||
"KEE" VARCHAR(50) NOT NULL, | |||
"RULE_ID" INTEGER, | |||
"SEVERITY" VARCHAR(10), | |||
"MANUAL_SEVERITY" BOOLEAN NOT NULL, | |||
"MESSAGE" VARCHAR(4000), | |||
"LINE" INTEGER, | |||
"GAP" DOUBLE, | |||
"STATUS" VARCHAR(20), | |||
"RESOLUTION" VARCHAR(20), | |||
"CHECKSUM" VARCHAR(1000), | |||
"REPORTER" VARCHAR(255), | |||
"ASSIGNEE" VARCHAR(255), | |||
"AUTHOR_LOGIN" VARCHAR(255), | |||
"ACTION_PLAN_KEY" VARCHAR(50), | |||
"ISSUE_ATTRIBUTES" VARCHAR(4000), | |||
"EFFORT" INTEGER, | |||
"CREATED_AT" BIGINT, | |||
"UPDATED_AT" BIGINT, | |||
"ISSUE_CREATION_DATE" BIGINT, | |||
"ISSUE_UPDATE_DATE" BIGINT, | |||
"ISSUE_CLOSE_DATE" BIGINT, | |||
"TAGS" VARCHAR(4000), | |||
"COMPONENT_UUID" VARCHAR(50), | |||
"PROJECT_UUID" VARCHAR(50), | |||
"LOCATIONS" BLOB, | |||
"ISSUE_TYPE" TINYINT, | |||
"FROM_HOTSPOT" BOOLEAN | |||
); | |||
ALTER TABLE "ISSUES" ADD CONSTRAINT "PK_ISSUES" PRIMARY KEY("ID"); | |||
CREATE INDEX "ISSUES_ASSIGNEE" ON "ISSUES"("ASSIGNEE"); | |||
CREATE INDEX "ISSUES_COMPONENT_UUID" ON "ISSUES"("COMPONENT_UUID"); | |||
CREATE INDEX "ISSUES_CREATION_DATE" ON "ISSUES"("ISSUE_CREATION_DATE"); | |||
CREATE UNIQUE INDEX "ISSUES_KEE" ON "ISSUES"("KEE"); | |||
CREATE INDEX "ISSUES_PROJECT_UUID" ON "ISSUES"("PROJECT_UUID"); | |||
CREATE INDEX "ISSUES_RESOLUTION" ON "ISSUES"("RESOLUTION"); | |||
CREATE INDEX "ISSUES_RULE_ID" ON "ISSUES"("RULE_ID"); | |||
CREATE INDEX "ISSUES_UPDATED_AT" ON "ISSUES"("UPDATED_AT"); | |||
CREATE TABLE "ISSUE_CHANGES"( | |||
"ID" BIGINT NOT NULL AUTO_INCREMENT (1,1), | |||
"KEE" VARCHAR(50), | |||
"ISSUE_KEY" VARCHAR(50) NOT NULL, | |||
"USER_LOGIN" VARCHAR(255), | |||
"CHANGE_TYPE" VARCHAR(20), | |||
"CHANGE_DATA" CLOB(2147483647), | |||
"CREATED_AT" BIGINT, | |||
"UPDATED_AT" BIGINT, | |||
"ISSUE_CHANGE_CREATION_DATE" BIGINT | |||
); | |||
ALTER TABLE "ISSUE_CHANGES" ADD CONSTRAINT "PK_ISSUE_CHANGES" PRIMARY KEY("ID"); | |||
CREATE INDEX "ISSUE_CHANGES_ISSUE_KEY" ON "ISSUE_CHANGES"("ISSUE_KEY"); | |||
CREATE INDEX "ISSUE_CHANGES_KEE" ON "ISSUE_CHANGES"("KEE"); |
@@ -28,19 +28,17 @@ public class SecurityStandardCategoryStatistics { | |||
private final String category; | |||
private final long vulnerabilities; | |||
private final OptionalInt vulnerabiliyRating; | |||
private final long inReviewSecurityHotspots; | |||
private final long toReviewSecurityHotspots; | |||
private final long reviewedSecurityHotspots; | |||
private final List<SecurityStandardCategoryStatistics> children; | |||
private long activeRules; | |||
private long totalRules; | |||
public SecurityStandardCategoryStatistics(String category, long vulnerabilities, OptionalInt vulnerabiliyRating, long inReviewSecurityHotspots, long toReviewSecurityHotspots, | |||
public SecurityStandardCategoryStatistics(String category, long vulnerabilities, OptionalInt vulnerabiliyRating, long toReviewSecurityHotspots, | |||
long reviewedSecurityHotspots, @Nullable List<SecurityStandardCategoryStatistics> children) { | |||
this.category = category; | |||
this.vulnerabilities = vulnerabilities; | |||
this.vulnerabiliyRating = vulnerabiliyRating; | |||
this.inReviewSecurityHotspots = inReviewSecurityHotspots; | |||
this.toReviewSecurityHotspots = toReviewSecurityHotspots; | |||
this.reviewedSecurityHotspots = reviewedSecurityHotspots; | |||
this.children = children; | |||
@@ -58,10 +56,6 @@ public class SecurityStandardCategoryStatistics { | |||
return vulnerabiliyRating; | |||
} | |||
public long getInReviewSecurityHotspots() { | |||
return inReviewSecurityHotspots; | |||
} | |||
public long getToReviewSecurityHotspots() { | |||
return toReviewSecurityHotspots; | |||
} |
@@ -39,7 +39,6 @@ import static org.sonar.api.issue.Issue.RESOLUTION_REMOVED; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX; | |||
import static org.sonar.api.issue.Issue.STATUS_CLOSED; | |||
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; | |||
import static org.sonar.api.issue.Issue.STATUS_IN_REVIEW; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_REOPENED; | |||
import static org.sonar.api.issue.Issue.STATUS_RESOLVED; | |||
@@ -64,7 +63,7 @@ public class IssueWorkflow implements Startable { | |||
public void start() { | |||
StateMachine.Builder builder = StateMachine.builder() | |||
.states(STATUS_OPEN, STATUS_CONFIRMED, STATUS_REOPENED, STATUS_RESOLVED, STATUS_CLOSED, | |||
STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED); | |||
STATUS_TO_REVIEW, STATUS_REVIEWED); | |||
buildManualTransitions(builder); | |||
buildAutomaticTransitions(builder); | |||
buildSecurityHotspotTransitions(builder); | |||
@@ -160,23 +159,12 @@ public class IssueWorkflow implements Startable { | |||
private static void buildSecurityHotspotTransitions(StateMachine.Builder builder) { | |||
builder | |||
.transition(Transition.builder(DefaultTransitions.SET_AS_IN_REVIEW) | |||
.from(STATUS_TO_REVIEW).to(STATUS_IN_REVIEW) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE_AS_REVIEWED) | |||
.from(STATUS_TO_REVIEW).to(STATUS_REVIEWED) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE_AS_REVIEWED) | |||
.from(STATUS_IN_REVIEW).to(STATUS_REVIEWED) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE_AS_REVIEWED) | |||
.from(STATUS_OPEN).to(STATUS_REVIEWED) | |||
.conditions(new HasType(RuleType.VULNERABILITY), IsManualVulnerability.INSTANCE) | |||
@@ -190,12 +178,6 @@ public class IssueWorkflow implements Startable { | |||
.functions(new SetResolution(null), new SetType(RuleType.VULNERABILITY)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.OPEN_AS_VULNERABILITY) | |||
.from(STATUS_IN_REVIEW).to(STATUS_OPEN) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(new SetType(RuleType.VULNERABILITY)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.OPEN_AS_VULNERABILITY) | |||
.from(STATUS_TO_REVIEW).to(STATUS_OPEN) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
@@ -203,12 +185,6 @@ public class IssueWorkflow implements Startable { | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESET_AS_TO_REVIEW) | |||
.from(STATUS_IN_REVIEW).to(STATUS_TO_REVIEW) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(new SetResolution(null)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESET_AS_TO_REVIEW) | |||
.from(STATUS_REVIEWED).to(STATUS_TO_REVIEW) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
@@ -257,12 +233,6 @@ public class IssueWorkflow implements Startable { | |||
.functions(SetClosed.INSTANCE, SetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
.transition(Transition.builder(AUTOMATIC_CLOSE_TRANSITION) | |||
.from(STATUS_IN_REVIEW).to(STATUS_CLOSED) | |||
.conditions(IsBeingClosed.INSTANCE, new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(SetClosed.INSTANCE, SetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
.transition(Transition.builder(AUTOMATIC_CLOSE_TRANSITION) | |||
.from(STATUS_REVIEWED).to(STATUS_CLOSED) | |||
.conditions(IsBeingClosed.INSTANCE, new HasType(RuleType.SECURITY_HOTSPOT)) |
@@ -44,7 +44,6 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_REMOVED; | |||
import static org.sonar.api.issue.Issue.STATUS_CLOSED; | |||
import static org.sonar.api.issue.Issue.STATUS_IN_REVIEW; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_RESOLVED; | |||
import static org.sonar.api.issue.Issue.STATUS_REVIEWED; | |||
@@ -54,7 +53,7 @@ import static org.sonar.db.rule.RuleTesting.XOO_X1; | |||
@RunWith(DataProviderRunner.class) | |||
public class IssueWorkflowForSecurityHotspotsTest { | |||
private static final String[] ALL_STATUSES_LEADING_TO_CLOSED = new String[] {STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_RESOLVED}; | |||
private static final String[] ALL_STATUSES_LEADING_TO_CLOSED = new String[] {STATUS_TO_REVIEW, STATUS_RESOLVED}; | |||
private static final String[] SUPPORTED_RESOLUTIONS_FOR_UNCLOSING = new String[] {RESOLUTION_FIXED, RESOLUTION_REMOVED}; | |||
@@ -94,17 +93,7 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
List<Transition> transitions = underTest.outTransitions(issue); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("setinreview", "resolveasreviewed", "openasvulnerability"); | |||
} | |||
@Test | |||
public void list_out_transitions_in_status_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue().setType(RuleType.SECURITY_HOTSPOT).setStatus(STATUS_IN_REVIEW); | |||
List<Transition> transitions = underTest.outTransitions(issue); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed", "openasvulnerability", "resetastoreview"); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed", "openasvulnerability"); | |||
} | |||
@Test | |||
@@ -127,21 +116,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed", "resetastoreview"); | |||
} | |||
@Test | |||
public void set_as_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_TO_REVIEW); | |||
boolean result = underTest.doManualTransition(issue, DefaultTransitions.SET_AS_IN_REVIEW, IssueChangeContext.createUser(new Date(), "USER1")); | |||
assertThat(result).isTrue(); | |||
assertThat(issue.getStatus()).isEqualTo(STATUS_IN_REVIEW); | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
public void resolve_as_reviewed_from_to_review() { | |||
underTest.start(); | |||
@@ -157,39 +131,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED); | |||
} | |||
@Test | |||
public void resolve_as_reviewed_from_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_IN_REVIEW) | |||
.setResolution(null); | |||
boolean result = underTest.doManualTransition(issue, DefaultTransitions.RESOLVE_AS_REVIEWED, IssueChangeContext.createUser(new Date(), "USER1")); | |||
assertThat(result).isTrue(); | |||
assertThat(issue.getStatus()).isEqualTo(STATUS_REVIEWED); | |||
assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED); | |||
} | |||
@Test | |||
public void open_as_vulnerability_from_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_IN_REVIEW) | |||
.setResolution(null); | |||
boolean result = underTest.doManualTransition(issue, DefaultTransitions.OPEN_AS_VULNERABILITY, IssueChangeContext.createUser(new Date(), "USER1")); | |||
assertThat(result).isTrue(); | |||
assertThat(issue.type()).isEqualTo(RuleType.VULNERABILITY); | |||
assertThat(issue.getStatus()).isEqualTo(Issue.STATUS_OPEN); | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
public void open_as_vulnerability_from_to_review() { | |||
underTest.start(); | |||
@@ -240,22 +181,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
public void reset_as_to_review_from_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_IN_REVIEW) | |||
.setResolution(null); | |||
boolean result = underTest.doManualTransition(issue, DefaultTransitions.RESET_AS_TO_REVIEW, IssueChangeContext.createUser(new Date(), "USER1")); | |||
assertThat(result).isTrue(); | |||
assertThat(issue.type()).isEqualTo(RuleType.SECURITY_HOTSPOT); | |||
assertThat(issue.getStatus()).isEqualTo(STATUS_TO_REVIEW); | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
public void reset_as_to_review_from_opened_as_vulnerability() { | |||
underTest.start(); | |||
@@ -291,25 +216,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND)); | |||
} | |||
@Test | |||
public void automatically_close_resolved_security_hotspots_in_status_in_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setResolution(null) | |||
.setStatus(STATUS_IN_REVIEW) | |||
.setNew(false) | |||
.setBeingClosed(true); | |||
Date now = new Date(); | |||
underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); | |||
assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED); | |||
assertThat(issue.status()).isEqualTo(STATUS_CLOSED); | |||
assertThat(issue.closeDate()).isNotNull(); | |||
assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND)); | |||
} | |||
@Test | |||
public void automatically_close_resolved_security_hotspots_in_status_reviewed() { | |||
underTest.start(); |
@@ -51,7 +51,6 @@ import static org.sonar.api.issue.Issue.RESOLUTION_REMOVED; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_WONT_FIX; | |||
import static org.sonar.api.issue.Issue.STATUS_CLOSED; | |||
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; | |||
import static org.sonar.api.issue.Issue.STATUS_IN_REVIEW; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_REOPENED; | |||
import static org.sonar.api.issue.Issue.STATUS_RESOLVED; | |||
@@ -73,7 +72,7 @@ public class IssueWorkflowTest { | |||
// issues statuses | |||
expectedStatus.addAll(Arrays.asList(STATUS_OPEN, STATUS_CONFIRMED, STATUS_REOPENED, STATUS_RESOLVED, STATUS_CLOSED)); | |||
// hostpots statuses | |||
expectedStatus.addAll(Arrays.asList(STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)); | |||
expectedStatus.addAll(Arrays.asList(STATUS_TO_REVIEW, STATUS_REVIEWED)); | |||
assertThat(underTest.statusKeys()).containsExactlyInAnyOrder(expectedStatus.toArray(new String[]{})); | |||
} |
@@ -930,12 +930,10 @@ public class IssueIndex { | |||
long toReviewSecurityHotspots = ((InternalValueCount) ((InternalFilter) categoryBucket.getAggregations().get(AGG_TO_REVIEW_SECURITY_HOTSPOTS)).getAggregations().get(AGG_COUNT)) | |||
.getValue(); | |||
long inReviewSecurityHotspots = ((InternalValueCount) ((InternalFilter) categoryBucket.getAggregations().get(AGG_IN_REVIEW_SECURITY_HOTSPOTS)).getAggregations().get(AGG_COUNT)) | |||
.getValue(); | |||
long reviewedSecurityHotspots = ((InternalValueCount) ((InternalFilter) categoryBucket.getAggregations().get(AGG_REVIEWED_SECURITY_HOTSPOTS)).getAggregations().get(AGG_COUNT)) | |||
.getValue(); | |||
return new SecurityStandardCategoryStatistics(categoryName, vulnerabilities, severityRating, inReviewSecurityHotspots, toReviewSecurityHotspots, | |||
return new SecurityStandardCategoryStatistics(categoryName, vulnerabilities, severityRating, toReviewSecurityHotspots, | |||
reviewedSecurityHotspots, children); | |||
} | |||
@@ -26,11 +26,11 @@ import java.util.stream.Collectors; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
@@ -176,49 +176,52 @@ public class IssueIndexSecurityReportsTest { | |||
assertThat(cweByOwasp.get("a1")).extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities, | |||
SecurityStandardCategoryStatistics::getVulnerabiliyRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots, | |||
SecurityStandardCategoryStatistics::getInReviewSecurityHotspots, SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
.containsExactlyInAnyOrder( | |||
tuple("123", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L, 0L), | |||
tuple("456", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L, 0L), | |||
tuple("unknown", 0L, OptionalInt.empty(), 1L /* openhotspot1 */, 0L, 0L)); | |||
tuple("123", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L), | |||
tuple("456", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L), | |||
tuple("unknown", 0L, OptionalInt.empty(), 1L /* openhotspot1 */, 0L)); | |||
assertThat(cweByOwasp.get("a3")).extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities, | |||
SecurityStandardCategoryStatistics::getVulnerabiliyRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots, | |||
SecurityStandardCategoryStatistics::getInReviewSecurityHotspots, SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
.containsExactlyInAnyOrder( | |||
tuple("123", 2L /* openvul1, openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L, 0L), | |||
tuple("456", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 1L /* toReviewHotspot */, 0L), | |||
tuple("unknown", 0L, OptionalInt.empty(), 1L /* openhotspot1 */, 0L, 0L)); | |||
tuple("123", 2L /* openvul1, openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 0L, 0L), | |||
tuple("456", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 0L/* toReviewHotspot */, 0L), | |||
tuple("unknown", 0L, OptionalInt.empty(), 1L /* openhotspot1 */, 0L)); | |||
} | |||
private List<SecurityStandardCategoryStatistics> indexIssuesAndAssertOwaspReport(boolean includeCwe) { | |||
OrganizationDto org = newOrganizationDto(); | |||
ComponentDto project = newPrivateProjectDto(org); | |||
indexIssues( | |||
newDoc("openvul1", project).setOwaspTop10(asList("a1", "a3")).setCwe(asList("123", "456")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.MAJOR), | |||
newDoc("openvul2", project).setOwaspTop10(asList("a3", "a6")).setCwe(asList("123")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED).setSeverity(Severity.MINOR), | |||
newDoc("openvul1", project).setOwaspTop10(asList("a1", "a3")).setCwe(asList("123", "456")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN) | |||
.setSeverity(Severity.MAJOR), | |||
newDoc("openvul2", project).setOwaspTop10(asList("a3", "a6")).setCwe(asList("123")).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_REOPENED) | |||
.setSeverity(Severity.MINOR), | |||
newDoc("notowaspvul", project).setOwaspTop10(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL), | |||
newDoc("toreviewhotspot1", project).setOwaspTop10(asList("a1", "a3")).setCwe(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot1", project).setOwaspTop10(asList("a1", "a3")).setCwe(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT) | |||
.setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot2", project).setOwaspTop10(asList("a3", "a6")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("inreviewhotspot", project).setOwaspTop10(asList("a5", "a3")).setCwe(asList("456")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_IN_REVIEW), | |||
newDoc("reviewedHotspot", project).setOwaspTop10(asList("a3", "a8")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("reviewedHotspot", project).setOwaspTop10(asList("a3", "a8")).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED) | |||
.setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("notowasphotspot", project).setOwaspTop10(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW)); | |||
List<SecurityStandardCategoryStatistics> owaspTop10Report = underTest.getOwaspTop10Report(project.uuid(), false, includeCwe); | |||
assertThat(owaspTop10Report) | |||
.extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities, | |||
SecurityStandardCategoryStatistics::getVulnerabiliyRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots, | |||
SecurityStandardCategoryStatistics::getInReviewSecurityHotspots, SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
.containsExactlyInAnyOrder( | |||
tuple("a1", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L, 0L), | |||
tuple("a2", 0L, OptionalInt.empty(), 0L, 0L, 0L), | |||
tuple("a3", 2L /* openvul1,openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */, 1L /* inReviewHotspot */, 1L /* reviewedHotspot */), | |||
tuple("a4", 0L, OptionalInt.empty(), 0L, 0L, 0L), | |||
tuple("a5", 0L, OptionalInt.empty(), 0L, 1L/* inReviewHotspot */, 0L), | |||
tuple("a6", 1L /* openvul2 */, OptionalInt.of(2) /* MINOR = B */, 1L /* toreviewhotspot2 */, 0L, 0L), | |||
tuple("a7", 0L, OptionalInt.empty(), 0L, 0L, 0L), | |||
tuple("a8", 0L, OptionalInt.empty(), 0L, 0L, 1L /* reviewedHotspot */), | |||
tuple("a9", 0L, OptionalInt.empty(), 0L, 0L, 0L), | |||
tuple("a10", 0L, OptionalInt.empty(), 0L, 0L, 0L)); | |||
tuple("a1", 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L), | |||
tuple("a2", 0L, OptionalInt.empty(), 0L, 0L), | |||
tuple("a3", 2L /* openvul1,openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */, 1L /* reviewedHotspot */), | |||
tuple("a4", 0L, OptionalInt.empty(), 0L, 0L), | |||
tuple("a5", 0L, OptionalInt.empty(), 0L, 0L), | |||
tuple("a6", 1L /* openvul2 */, OptionalInt.of(2) /* MINOR = B */, 1L /* toreviewhotspot2 */, 0L), | |||
tuple("a7", 0L, OptionalInt.empty(), 0L, 0L), | |||
tuple("a8", 0L, OptionalInt.empty(), 0L, 1L /* reviewedHotspot */), | |||
tuple("a9", 0L, OptionalInt.empty(), 0L, 0L), | |||
tuple("a10", 0L, OptionalInt.empty(), 0L, 0L)); | |||
return owaspTop10Report; | |||
} | |||
@@ -235,21 +238,25 @@ public class IssueIndexSecurityReportsTest { | |||
.setResolution(Issue.RESOLUTION_FIXED) | |||
.setSeverity(Severity.BLOCKER), | |||
newDoc("notsansvul", project).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL), | |||
newDoc("toreviewhotspot1", project).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot2", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot1", project).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT) | |||
.setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot2", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT) | |||
.setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("inReviewHotspot", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_IN_REVIEW), | |||
newDoc("reviewedHotspot", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("reviewedHotspot", project).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED) | |||
.setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("notowasphotspot", project).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW)); | |||
List<SecurityStandardCategoryStatistics> sansTop25Report = underTest.getSansTop25Report(project.uuid(), false, false); | |||
assertThat(sansTop25Report) | |||
.extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities, | |||
SecurityStandardCategoryStatistics::getVulnerabiliyRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots, | |||
SecurityStandardCategoryStatistics::getInReviewSecurityHotspots, SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
.containsExactlyInAnyOrder( | |||
tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L, 0L), | |||
tuple(SANS_TOP_25_RISKY_RESOURCE, 2L /* openvul1,openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */, 1L /* inReviewHotspot */,1L /* reviewedHotspot */), | |||
tuple(SANS_TOP_25_POROUS_DEFENSES, 1L /* openvul2 */, OptionalInt.of(2)/* MINOR = B */, 1L/* openhotspot2 */, 0L, 0L)); | |||
tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L), | |||
tuple(SANS_TOP_25_RISKY_RESOURCE, 2L /* openvul1,openvul2 */, OptionalInt.of(3)/* MAJOR = C */, 2L/* toreviewhotspot1,toreviewhotspot2 */, | |||
1L /* reviewedHotspot */), | |||
tuple(SANS_TOP_25_POROUS_DEFENSES, 1L /* openvul2 */, OptionalInt.of(2)/* MINOR = B */, 1L/* openhotspot2 */, 0L)); | |||
assertThat(sansTop25Report).allMatch(category -> category.getChildren().isEmpty()); | |||
} | |||
@@ -270,10 +277,12 @@ public class IssueIndexSecurityReportsTest { | |||
.setResolution(Issue.RESOLUTION_FIXED) | |||
.setSeverity(Severity.BLOCKER), | |||
newDoc("notsansvul", project2).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.VULNERABILITY).setStatus(Issue.STATUS_OPEN).setSeverity(Severity.CRITICAL), | |||
newDoc("toreviewhotspot1", project1).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot2", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("inReviewHotspot", project1).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_IN_REVIEW), | |||
newDoc("reviewedHotspot", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("toreviewhotspot1", project1).setSansTop25(asList(SANS_TOP_25_INSECURE_INTERACTION, SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT) | |||
.setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("toreviewhotspot2", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE, SANS_TOP_25_POROUS_DEFENSES)).setType(RuleType.SECURITY_HOTSPOT) | |||
.setStatus(Issue.STATUS_TO_REVIEW), | |||
newDoc("reviewedHotspot", project2).setSansTop25(asList(SANS_TOP_25_RISKY_RESOURCE)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED) | |||
.setResolution(Issue.RESOLUTION_FIXED), | |||
newDoc("notowasphotspot", project1).setSansTop25(singletonList(UNKNOWN_STANDARD)).setType(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW)); | |||
indexView(portfolio1.uuid(), singletonList(project1.uuid())); | |||
@@ -283,11 +292,11 @@ public class IssueIndexSecurityReportsTest { | |||
assertThat(sansTop25Report) | |||
.extracting(SecurityStandardCategoryStatistics::getCategory, SecurityStandardCategoryStatistics::getVulnerabilities, | |||
SecurityStandardCategoryStatistics::getVulnerabiliyRating, SecurityStandardCategoryStatistics::getToReviewSecurityHotspots, | |||
SecurityStandardCategoryStatistics::getInReviewSecurityHotspots, SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
SecurityStandardCategoryStatistics::getReviewedSecurityHotspots) | |||
.containsExactlyInAnyOrder( | |||
tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L, 0L), | |||
tuple(SANS_TOP_25_RISKY_RESOURCE, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L/* toreviewhotspot1 */, 1L /* inReviewHotspot */, 0L), | |||
tuple(SANS_TOP_25_POROUS_DEFENSES, 0L, OptionalInt.empty(), 0L, 0L, 0L)); | |||
tuple(SANS_TOP_25_INSECURE_INTERACTION, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L /* toreviewhotspot1 */, 0L), | |||
tuple(SANS_TOP_25_RISKY_RESOURCE, 1L /* openvul1 */, OptionalInt.of(3)/* MAJOR = C */, 1L/* toreviewhotspot1 */, 0L), | |||
tuple(SANS_TOP_25_POROUS_DEFENSES, 0L, OptionalInt.empty(), 0L, 0L)); | |||
assertThat(sansTop25Report).allMatch(category -> category.getChildren().isEmpty()); | |||
} |
@@ -75,6 +75,7 @@ public class DoTransitionAction implements IssuesWsAction { | |||
"The transitions involving security hotspots require the permission 'Administer Security Hotspot'.") | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("8.1", SET_AS_IN_REVIEW + " transition has been deprecated"), | |||
new Change("7.8", format("added '%s', %s, %s and %s transitions for security hotspots ", SET_AS_IN_REVIEW, RESOLVE_AS_REVIEWED, OPEN_AS_VULNERABILITY, RESET_AS_TO_REVIEW)), | |||
new Change("7.3", "added transitions for security hotspots"), | |||
new Change("6.5", "the database ids of the components are removed from the response"), |
@@ -198,6 +198,7 @@ public class SearchAction implements IssuesWsAction, Startable { | |||
PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS) | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("8.1", format("Status %s for Security Hotspots has been deprecated", STATUS_IN_REVIEW)), | |||
new Change("7.8", format("added new Security Hotspots statuses : %s, %s and %s", STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)), | |||
new Change("7.8", "Security hotspots are returned by default"), | |||
new Change("7.7", format("Value '%s' in parameter '%s' is deprecated, please use '%s' instead", DEPRECATED_PARAM_AUTHORS, FACETS, PARAM_AUTHOR)), |
@@ -30,10 +30,10 @@ import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.impl.utils.TestSystem2; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchType; | |||
@@ -77,12 +77,12 @@ import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.sonar.api.issue.DefaultTransitions.SET_AS_IN_REVIEW; | |||
import static org.sonar.api.issue.DefaultTransitions.RESOLVE_AS_REVIEWED; | |||
import static org.sonar.api.issue.Issue.RESOLUTION_FIXED; | |||
import static org.sonar.api.issue.Issue.STATUS_CLOSED; | |||
import static org.sonar.api.issue.Issue.STATUS_CONFIRMED; | |||
import static org.sonar.api.issue.Issue.STATUS_IN_REVIEW; | |||
import static org.sonar.api.issue.Issue.STATUS_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_REVIEWED; | |||
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW; | |||
import static org.sonar.api.rule.Severity.MAJOR; | |||
import static org.sonar.api.rule.Severity.MINOR; | |||
@@ -347,7 +347,7 @@ public class BulkChangeActionTest { | |||
BulkChangeWsResponse response = call(builder() | |||
.setIssues(singletonList(issue.getKey())) | |||
.setDoTransition(SET_AS_IN_REVIEW) | |||
.setDoTransition(RESOLVE_AS_REVIEWED) | |||
.setSendNotifications(true) | |||
.build()); | |||
@@ -357,8 +357,8 @@ public class BulkChangeActionTest { | |||
assertThat(builder.getIssues()).hasSize(1); | |||
ChangedIssue changedIssue = builder.getIssues().iterator().next(); | |||
assertThat(changedIssue.getKey()).isEqualTo(issue.getKey()); | |||
assertThat(changedIssue.getNewStatus()).isEqualTo(STATUS_IN_REVIEW); | |||
assertThat(changedIssue.getNewResolution()).isEmpty(); | |||
assertThat(changedIssue.getNewStatus()).isEqualTo(STATUS_REVIEWED); | |||
assertThat(changedIssue.getNewResolution()).hasValue(RESOLUTION_FIXED); | |||
assertThat(changedIssue.getAssignee()).isEmpty(); | |||
assertThat(changedIssue.getRule()).isEqualTo(ruleOf(rule)); | |||
assertThat(builder.getChange()).isEqualTo(new UserChange(NOW, userOf(user))); |
@@ -115,7 +115,7 @@ public class SearchActionFacetsTest { | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("IN_REVIEW", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
@@ -153,7 +153,7 @@ public class SearchActionFacetsTest { | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 10L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("IN_REVIEW", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) | |||
@@ -448,7 +448,7 @@ public class SearchActionFacetsTest { | |||
// Assignees contains one additional element : it's the empty string that will return number of unassigned issues | |||
tuple("assignees", 101), | |||
// Following facets returned fixed number of elements | |||
tuple("statuses", 8), | |||
tuple("statuses", 7), | |||
tuple("resolutions", 5), | |||
tuple("severities", 5), | |||
tuple("types", 4)); | |||
@@ -507,7 +507,7 @@ public class SearchActionFacetsTest { | |||
.executeProtobuf(SearchWsResponse.class); | |||
Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L) | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("IN_REVIEW", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build(); | |||
assertThat(response.getFacets().getFacetsList()) | |||
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount))) |
@@ -42,7 +42,7 @@ public interface DefaultTransitions { | |||
String WONT_FIX = "wontfix"; | |||
/** | |||
* @since 7.8 | |||
* @deprecated since 8.1, transition has no effect | |||
*/ | |||
String SET_AS_IN_REVIEW = "setinreview"; | |||
@@ -82,8 +82,9 @@ public interface Issue extends Serializable { | |||
String STATUS_TO_REVIEW = "TO_REVIEW"; | |||
/** | |||
* @since 7.8 | |||
* @deprecated since 8.1, status has been mapped as `TO_REVIEW` | |||
*/ | |||
@Deprecated | |||
String STATUS_IN_REVIEW = "IN_REVIEW"; | |||
/** | |||
@@ -97,7 +98,7 @@ public interface Issue extends Serializable { | |||
* @since 4.4 | |||
*/ | |||
List<String> STATUSES = unmodifiableList(asList(STATUS_OPEN, STATUS_CONFIRMED, STATUS_REOPENED, STATUS_RESOLVED, STATUS_CLOSED, | |||
STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)); | |||
STATUS_TO_REVIEW, STATUS_REVIEWED)); | |||
/** | |||
* Unique generated key. It looks like "d2de809c-1512-4ae2-9f34-f5345c9f1a13". |
@@ -35,7 +35,6 @@ message SecurityStandardCategoryStatistics { | |||
optional string category = 1; | |||
optional int64 vulnerabilities = 2; | |||
optional int64 vulnerabilityRating = 3; | |||
optional int64 inReviewSecurityHotspots = 4; | |||
optional int64 toReviewSecurityHotspots = 5; | |||
optional int64 reviewedSecurityHotspots = 6; | |||
repeated CweStatistics distribution = 7; | |||
@@ -47,7 +46,6 @@ message CweStatistics { | |||
optional string cwe = 1; | |||
optional int64 vulnerabilities = 2; | |||
optional int64 vulnerabilityRating = 3; | |||
optional int64 inReviewSecurityHotspots = 4; | |||
optional int64 toReviewSecurityHotspots = 5; | |||
optional int64 reviewedSecurityHotspots = 6; | |||
optional int64 activeRules = 7; |