From b9e5b79c297f4978be1f4dd60922e2496ec6b01a Mon Sep 17 00:00:00 2001 From: Jacek Date: Thu, 28 Nov 2019 16:08:19 +0100 Subject: [PATCH] SONAR-12722 drop `in_review` status --- .../db/migration/version/v81/DbVersion81.java | 3 +- .../DropSecurityHotSpotsInReviewStatus.java | 58 +++++++++ .../version/v81/DbVersion81Test.java | 2 +- ...ropSecurityHotSpotsInReviewStatusTest.java | 118 ++++++++++++++++++ .../schema.sql | 54 ++++++++ .../SecurityStandardCategoryStatistics.java | 8 +- .../server/issue/workflow/IssueWorkflow.java | 32 +---- .../IssueWorkflowForSecurityHotspotsTest.java | 98 +-------------- .../issue/workflow/IssueWorkflowTest.java | 3 +- .../sonar/server/issue/index/IssueIndex.java | 4 +- .../index/IssueIndexSecurityReportsTest.java | 89 +++++++------ .../server/issue/ws/DoTransitionAction.java | 1 + .../sonar/server/issue/ws/SearchAction.java | 1 + .../server/issue/ws/BulkChangeActionTest.java | 12 +- .../issue/ws/SearchActionFacetsTest.java | 8 +- .../sonar/api/issue/DefaultTransitions.java | 2 +- .../main/java/org/sonar/api/issue/Issue.java | 5 +- sonar-ws/src/main/protobuf/ws-security.proto | 2 - 18 files changed, 304 insertions(+), 196 deletions(-) create mode 100644 server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatus.java create mode 100644 server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest.java create mode 100644 server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest/schema.sql diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java index 997f9362c41..f9a518f8978 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81.java @@ -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); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatus.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatus.java new file mode 100644 index 00000000000..7b1248d2c19 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatus.java @@ -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; + }); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java index 46c2f39dfd8..05e5efc4be1 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DbVersion81Test.java @@ -36,7 +36,7 @@ public class DbVersion81Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 14); + verifyMigrationCount(underTest, 15); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest.java new file mode 100644 index 00000000000..33272ea586a --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest.java @@ -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 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> 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> 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 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> 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> 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); + } + +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest/schema.sql new file mode 100644 index 00000000000..d8f2d4316ab --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v81/DropSecurityHotSpotsInReviewStatusTest/schema.sql @@ -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"); diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardCategoryStatistics.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardCategoryStatistics.java index 7e3082c8ce7..ea54b187792 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardCategoryStatistics.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/index/SecurityStandardCategoryStatistics.java @@ -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 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 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; } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java b/server/sonar-server-common/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java index 56b19117499..fd7046b917a 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java @@ -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)) diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowForSecurityHotspotsTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowForSecurityHotspotsTest.java index 3886de33764..d63b4f6cf3a 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowForSecurityHotspotsTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowForSecurityHotspotsTest.java @@ -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 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 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(); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowTest.java index 205627ad939..5e93500ee05 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/issue/workflow/IssueWorkflowTest.java @@ -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[]{})); } diff --git a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 64ce06bb210..221fbe817a8 100644 --- a/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-webserver-es/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -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); } diff --git a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java index 68833a8312d..1b75d334230 100644 --- a/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java +++ b/server/sonar-webserver-es/src/test/java/org/sonar/server/issue/index/IssueIndexSecurityReportsTest.java @@ -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 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 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 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()); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/DoTransitionAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/DoTransitionAction.java index 3906ce5dc65..a81c7b98496 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/DoTransitionAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/DoTransitionAction.java @@ -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"), diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java index 406d87c163c..f06ac22cdd4 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java @@ -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)), diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java index e1e446b9fc1..fd7988bd2ec 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/BulkChangeActionTest.java @@ -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))); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java index 30d14f3a35f..0981dccbb84 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java @@ -115,7 +115,7 @@ public class SearchActionFacetsTest { .executeProtobuf(SearchWsResponse.class); Map expectedStatuses = ImmutableMap.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 expectedStatuses = ImmutableMap.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 expectedStatuses = ImmutableMap.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))) diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/DefaultTransitions.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/DefaultTransitions.java index 7de13075ba6..defdfc3219b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/DefaultTransitions.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/DefaultTransitions.java @@ -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"; diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issue.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issue.java index 1475a54afea..6c831ca61f6 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issue.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/Issue.java @@ -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 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". diff --git a/sonar-ws/src/main/protobuf/ws-security.proto b/sonar-ws/src/main/protobuf/ws-security.proto index 67d7c7e7264..936455009cc 100644 --- a/sonar-ws/src/main/protobuf/ws-security.proto +++ b/sonar-ws/src/main/protobuf/ws-security.proto @@ -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; -- 2.39.5