* drop manual vulnerabilities * remove issues `from_hotspot` column usagetags/8.2.0.32929
@@ -76,7 +76,6 @@ public class IssueLifecycle { | |||
issue.setCreationDate(changeContext.date()); | |||
issue.setUpdateDate(changeContext.date()); | |||
issue.setEffort(debtCalculator.calculate(issue)); | |||
issue.setIsFromHotspot(rule.getType() == RuleType.SECURITY_HOTSPOT); | |||
setType(issue, rule); | |||
setStatus(issue, rule); | |||
} | |||
@@ -165,20 +164,9 @@ public class IssueLifecycle { | |||
// In case issue was moved from module or folder to the root project | |||
raw.setChanged(true); | |||
} | |||
raw.setIsFromHotspot(rule.getType() == RuleType.SECURITY_HOTSPOT); | |||
setType(raw, rule); | |||
copyFields(raw, base); | |||
base.changes().forEach(raw::addChange); | |||
if (raw.isFromHotspot() != base.isFromHotspot()) { | |||
// This is to force DB update of the issue | |||
raw.setChanged(true); | |||
} | |||
if (raw.isFromHotspot() && !base.isFromHotspot()) { | |||
// First analysis after rule type was changed to security_hotspot. Issue will be reset to an open hotspot | |||
updater.setType(raw, RuleType.SECURITY_HOTSPOT, changeContext); | |||
updater.setStatus(raw, Issue.STATUS_TO_REVIEW, changeContext); | |||
updater.setResolution(raw, null, changeContext); | |||
} | |||
if (base.manualSeverity()) { | |||
raw.setManualSeverity(true); |
@@ -80,7 +80,7 @@ public class ComponentIssuesLoaderTest { | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insert(t -> t.setType(CODE_SMELL)); | |||
Date issueDate = addDays(NOW, -10); | |||
IssueDto issue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL).setIsFromHotspot(false)); | |||
IssueDto issue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(issueDate, 10)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(addDays(issueDate, 3), 20)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(addDays(issueDate, 1), 30)); | |||
@@ -100,7 +100,7 @@ public class ComponentIssuesLoaderTest { | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insert(t -> t.setType(CODE_SMELL)); | |||
Date issueDate = addDays(NOW, -10); | |||
IssueDto issue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL).setIsFromHotspot(false)); | |||
IssueDto issue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(issueDate, 10)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(addDays(issueDate, 2), null)); | |||
db.issues().insertFieldDiffs(issue, newToClosedDiffsWithLine(addDays(issueDate, 1), 30)); | |||
@@ -120,9 +120,9 @@ public class ComponentIssuesLoaderTest { | |||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||
RuleDefinitionDto rule = db.rules().insert(t -> t.setType(CODE_SMELL)); | |||
Date issueDate = addDays(NOW, -10); | |||
IssueDto closedIssue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL).setIsFromHotspot(false)); | |||
IssueDto closedIssue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL)); | |||
db.issues().insertFieldDiffs(closedIssue, newToClosedDiffsWithLine(issueDate, 10)); | |||
IssueDto issueNoCloseDate = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIsFromHotspot(false)); | |||
IssueDto issueNoCloseDate = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED)); | |||
db.issues().insertFieldDiffs(issueNoCloseDate, newToClosedDiffsWithLine(issueDate, 10)); | |||
when(system2.now()).thenReturn(NOW.getTime()); | |||
@@ -198,7 +198,7 @@ public class ComponentIssuesLoaderTest { | |||
}; | |||
IssueDto[] issues = Arrays.stream(issueDates) | |||
.map(issueDate -> { | |||
IssueDto closedIssue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL).setIsFromHotspot(false)); | |||
IssueDto closedIssue = db.issues().insert(rule, project, file, t -> t.setStatus(STATUS_CLOSED).setIssueCloseDate(issueDate).setType(CODE_SMELL)); | |||
db.issues().insertFieldDiffs(closedIssue, newToClosedDiffsWithLine(issueDate, 10)); | |||
return closedIssue; | |||
}) |
@@ -87,7 +87,6 @@ public class IssueLifecycleTest { | |||
assertThat(issue.effort()).isEqualTo(DEFAULT_DURATION); | |||
assertThat(issue.isNew()).isTrue(); | |||
assertThat(issue.isCopied()).isFalse(); | |||
assertThat(issue.isFromHotspot()).isFalse(); | |||
} | |||
@Test | |||
@@ -107,7 +106,6 @@ public class IssueLifecycleTest { | |||
assertThat(issue.effort()).isEqualTo(DEFAULT_DURATION); | |||
assertThat(issue.isNew()).isTrue(); | |||
assertThat(issue.isCopied()).isFalse(); | |||
assertThat(issue.isFromHotspot()).isTrue(); | |||
} | |||
@Test | |||
@@ -303,70 +301,6 @@ public class IssueLifecycleTest { | |||
verify(updater).setPastLocations(raw, issueLocations); | |||
} | |||
@Test | |||
public void mergeExistingOpenIssue_vulnerability_changed_to_hotspot_should_be_to_review() { | |||
rule.setType(RuleType.SECURITY_HOTSPOT); | |||
DefaultIssue raw = new DefaultIssue() | |||
.setNew(true) | |||
.setKey("RAW_KEY") | |||
.setRuleKey(XOO_X1) | |||
.setCreationDate(parseDate("2015-10-01")) | |||
.setUpdateDate(parseDate("2015-10-02")) | |||
.setCloseDate(parseDate("2015-10-03")); | |||
DbIssues.Locations issueLocations = DbIssues.Locations.newBuilder() | |||
.setTextRange(DbCommons.TextRange.newBuilder() | |||
.setStartLine(10) | |||
.setEndLine(12) | |||
.build()) | |||
.build(); | |||
DefaultIssue base = new DefaultIssue() | |||
.setKey("BASE_KEY") | |||
.setType(RuleType.VULNERABILITY) | |||
// First analysis before rule was changed to hotspot | |||
.setIsFromHotspot(false) | |||
.setCreationDate(parseDate("2015-01-01")) | |||
.setUpdateDate(parseDate("2015-01-02")) | |||
.setResolution(RESOLUTION_FALSE_POSITIVE) | |||
.setStatus(STATUS_RESOLVED) | |||
.setSeverity(BLOCKER) | |||
.setAssigneeUuid("base assignee uuid") | |||
.setAuthorLogin("base author") | |||
.setTags(newArrayList("base tag")) | |||
.setSelectedAt(1000L) | |||
.setLine(10) | |||
.setMessage("message") | |||
.setGap(15d) | |||
.setEffort(Duration.create(15L)) | |||
.setManualSeverity(false) | |||
.setLocations(issueLocations); | |||
when(debtCalculator.calculate(raw)).thenReturn(DEFAULT_DURATION); | |||
underTest.mergeExistingOpenIssue(raw, base); | |||
assertThat(raw.isNew()).isFalse(); | |||
assertThat(raw.key()).isEqualTo("BASE_KEY"); | |||
assertThat(raw.creationDate()).isEqualTo(base.creationDate()); | |||
assertThat(raw.updateDate()).isEqualTo(base.updateDate()); | |||
assertThat(raw.assignee()).isEqualTo("base assignee uuid"); | |||
assertThat(raw.authorLogin()).isEqualTo("base author"); | |||
assertThat(raw.tags()).containsOnly("base tag"); | |||
assertThat(raw.effort()).isEqualTo(DEFAULT_DURATION); | |||
assertThat(raw.selectedAt()).isEqualTo(1000L); | |||
assertThat(raw.isFromHotspot()).isTrue(); | |||
assertThat(raw.isChanged()).isTrue(); | |||
verify(updater).setType(raw, RuleType.SECURITY_HOTSPOT, issueChangeContext); | |||
verify(updater).setStatus(raw, STATUS_TO_REVIEW, issueChangeContext); | |||
verify(updater).setResolution(raw, null, issueChangeContext); | |||
verify(updater).setPastSeverity(raw, BLOCKER, issueChangeContext); | |||
verify(updater).setPastLine(raw, 10); | |||
verify(updater).setPastMessage(raw, "message", issueChangeContext); | |||
verify(updater).setPastEffort(raw, Duration.create(15L), issueChangeContext); | |||
verify(updater).setPastLocations(raw, issueLocations); | |||
} | |||
@Test | |||
public void mergeExistingOpenIssue_with_manual_severity() { | |||
DefaultIssue raw = new DefaultIssue() |
@@ -122,7 +122,6 @@ public final class IssueDto implements Serializable { | |||
.setRuleId(ruleId) | |||
.setRuleKey(issue.ruleKey().repository(), issue.ruleKey().rule()) | |||
.setExternal(issue.isFromExternalRuleEngine()) | |||
.setIsFromHotspot(issue.isFromHotspot()) | |||
.setTags(issue.tags()) | |||
.setComponentUuid(issue.componentUuid()) | |||
.setComponentKey(issue.componentKey()) | |||
@@ -171,7 +170,6 @@ public final class IssueDto implements Serializable { | |||
.setAuthorLogin(issue.authorLogin()) | |||
.setRuleKey(issue.ruleKey().repository(), issue.ruleKey().rule()) | |||
.setExternal(issue.isFromExternalRuleEngine()) | |||
.setIsFromHotspot(issue.isFromHotspot()) | |||
.setTags(issue.tags()) | |||
.setComponentUuid(issue.componentUuid()) | |||
.setComponentKey(issue.componentKey()) | |||
@@ -489,15 +487,6 @@ public final class IssueDto implements Serializable { | |||
return this; | |||
} | |||
public boolean isFromHotspot() { | |||
return isFromHotspot; | |||
} | |||
public IssueDto setIsFromHotspot(boolean value) { | |||
isFromHotspot = value; | |||
return this; | |||
} | |||
public String getComponentKey() { | |||
return componentKey; | |||
} | |||
@@ -742,7 +731,6 @@ public final class IssueDto implements Serializable { | |||
issue.setSelectedAt(selectedAt); | |||
issue.setLocations(parseLocations()); | |||
issue.setIsFromExternalRuleEngine(isExternal); | |||
issue.setIsFromHotspot(isFromHotspot); | |||
return issue; | |||
} | |||
} |
@@ -38,8 +38,7 @@ | |||
p.path as filePath, | |||
root.kee as projectKey, | |||
i.project_uuid as projectUuid, | |||
i.issue_type as type, | |||
i.from_hotspot as "isFromHotspot" | |||
i.issue_type as type | |||
</sql> | |||
<sql id="sortColumn"> | |||
@@ -96,8 +95,7 @@ | |||
p.scope, | |||
p.organization_uuid as "organizationUuid", | |||
i.tags, | |||
i.issue_type as "issueType", | |||
i.from_hotspot as "isFromHotspot" | |||
i.issue_type as "issueType" | |||
</sql> | |||
@@ -105,7 +103,7 @@ | |||
INSERT INTO issues (kee, rule_id, severity, manual_severity, | |||
message, line, locations, gap, effort, status, tags, | |||
resolution, checksum, assignee, author_login, issue_attributes, issue_creation_date, issue_update_date, | |||
issue_close_date, created_at, updated_at, component_uuid, project_uuid, issue_type, from_hotspot) | |||
issue_close_date, created_at, updated_at, component_uuid, project_uuid, issue_type) | |||
VALUES (#{kee,jdbcType=VARCHAR}, #{ruleId,jdbcType=INTEGER}, | |||
#{severity,jdbcType=VARCHAR}, | |||
#{manualSeverity,jdbcType=BOOLEAN}, #{message,jdbcType=VARCHAR}, #{line,jdbcType=INTEGER}, | |||
@@ -118,7 +116,7 @@ | |||
#{issueAttributes,jdbcType=VARCHAR}, | |||
#{issueCreationTime,jdbcType=BIGINT},#{issueUpdateTime,jdbcType=BIGINT}, #{issueCloseTime,jdbcType=BIGINT}, | |||
#{createdAt,jdbcType=BIGINT}, #{updatedAt,jdbcType=BIGINT}, | |||
#{componentUuid,jdbcType=VARCHAR}, #{projectUuid,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}, #{isFromHotspot,jdbcType=BOOLEAN}) | |||
#{componentUuid,jdbcType=VARCHAR}, #{projectUuid,jdbcType=VARCHAR}, #{type,jdbcType=INTEGER}) | |||
</insert> | |||
<!-- | |||
@@ -145,8 +143,7 @@ | |||
issue_update_date=#{issueUpdateTime,jdbcType=BIGINT}, | |||
issue_close_date=#{issueCloseTime,jdbcType=BIGINT}, | |||
updated_at=#{updatedAt,jdbcType=BIGINT}, | |||
issue_type=#{type,jdbcType=INTEGER}, | |||
from_hotspot=#{isFromHotspot,jdbcType=BOOLEAN} | |||
issue_type=#{type,jdbcType=INTEGER} | |||
where kee = #{kee} | |||
</update> | |||
@@ -175,8 +172,7 @@ | |||
issue_update_date=#{issueUpdateTime,jdbcType=BIGINT}, | |||
issue_close_date=#{issueCloseTime,jdbcType=BIGINT}, | |||
updated_at=#{updatedAt,jdbcType=BIGINT}, | |||
issue_type=#{type,jdbcType=INTEGER}, | |||
from_hotspot=#{isFromHotspot,jdbcType=BOOLEAN} | |||
issue_type=#{type,jdbcType=INTEGER} | |||
where kee = #{kee} and updated_at <= #{selectedAt} | |||
</update> | |||
@@ -213,7 +209,7 @@ | |||
(r.is_external is NULL or r.is_external = ${_false}) and | |||
i.component_uuid = #{componentUuid,jdbcType=VARCHAR} and | |||
i.status <> 'CLOSED' and | |||
i.issue_type <> 4 and (i.from_hotspot is NULL or i.from_hotspot = ${_false}) | |||
i.issue_type <> 4 | |||
</select> | |||
<select id="scrollClosedByComponentUuid" resultType="Issue" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||
@@ -237,7 +233,6 @@ | |||
and i.issue_close_date is not null | |||
and i.issue_close_date >= #{closeDateAfter,jdbcType=BIGINT} | |||
and i.issue_type <> 4 | |||
and (i.from_hotspot is null or i.from_hotspot = ${_false}) | |||
order by | |||
i.kee, ic.issue_change_creation_date desc | |||
</select> | |||
@@ -323,7 +318,7 @@ | |||
i.project_uuid = #{projectUuid, jdbcType=VARCHAR} and | |||
p.module_uuid_path like #{likeModuleUuidPath, jdbcType=VARCHAR} escape '/' and | |||
i.status <> 'CLOSED' and | |||
i.issue_type <> 4 and (i.from_hotspot is NULL or i.from_hotspot = ${_false}) | |||
i.issue_type <> 4 | |||
</select> | |||
<select id="selectIssueGroupsByBaseComponent" resultType="org.sonar.db.issue.IssueGroupDto" parameterType="map"> |
@@ -142,7 +142,6 @@ public class IssueDaoTest { | |||
IssueDto openIssueOnProject = db.issues().insert(rule, project, project, i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot())); | |||
IssueDto securityHotspot = db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT)); | |||
IssueDto manualVulnerability = db.issues().insert(rule, project, file, i -> i.setType(RuleType.VULNERABILITY).setIsFromHotspot(true)); | |||
RuleDefinitionDto external = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setIsExternal(true)); | |||
IssueDto issueFromExteralruleOnFile = db.issues().insert(external, project, file, i -> i.setKee("ON_FILE_FROM_EXTERNAL").setType(randomRuleTypeExceptHotspot())); | |||
@@ -174,7 +173,6 @@ public class IssueDaoTest { | |||
i -> i.setStatus("OPEN").setResolution(null).setType(randomRuleTypeExceptHotspot())); | |||
IssueDto securityHotspot = db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT)); | |||
IssueDto manualVulnerability = db.issues().insert(rule, project, file, i -> i.setType(RuleType.VULNERABILITY).setIsFromHotspot(true)); | |||
RuleDefinitionDto external = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setIsExternal(true)); | |||
IssueDto issueFromExteralruleOnFile = db.issues().insert(external, project, file, i -> i.setKee("ON_FILE_FROM_EXTERNAL").setType(randomRuleTypeExceptHotspot())); |
@@ -340,27 +340,6 @@ public class IssueMapperTest { | |||
.containsOnly(tuple(issue.getKey(), issueChange.getChangeData())); | |||
} | |||
@Test | |||
public void scrollClosedByComponentUuid_returns_closed_issues_without_isHotspot_flag() { | |||
RuleType ruleType = randomSupportedRuleType(); | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto component = randomComponent(organization); | |||
IssueDto noHotspotFlagIssue = insertNewClosedIssue(component, ruleType); | |||
IssueChangeDto noFlagIssueChange = insertToClosedDiff(noHotspotFlagIssue); | |||
manuallySetToNullFromHotpotsColumn(noHotspotFlagIssue); | |||
IssueDto issue = insertNewClosedIssue(component, ruleType); | |||
IssueChangeDto issueChange = insertToClosedDiff(issue); | |||
RecorderResultHandler resultHandler = new RecorderResultHandler(); | |||
underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler); | |||
assertThat(resultHandler.issues) | |||
.extracting(IssueDto::getKey, t -> t.getClosedChangeData().get()) | |||
.containsOnly( | |||
tuple(issue.getKey(), issueChange.getChangeData()), | |||
tuple(noHotspotFlagIssue.getKey(), noFlagIssueChange.getChangeData())); | |||
} | |||
@Test | |||
public void scrollClosedByComponentUuid_does_not_return_closed_issues_without_close_date() { | |||
RuleType ruleType = randomSupportedRuleType(); | |||
@@ -428,29 +407,6 @@ public class IssueMapperTest { | |||
.containsOnly(issues[3].getKey(), issues[1].getKey(), issues[2].getKey(), issues[0].getKey()); | |||
} | |||
private void manuallySetToNullFromHotpotsColumn(IssueDto fromHostSpotIssue) { | |||
dbTester.executeUpdateSql("update issues set from_hotspot = null where kee = '" + fromHostSpotIssue.getKey() + "'"); | |||
dbTester.commit(); | |||
} | |||
@Test | |||
@UseDataProvider("closedIssuesSupportedRuleTypes") | |||
public void scrollClosedByComponentUuid_does_not_return_closed_issues_with_isHotspot_flag_true(RuleType ruleType) { | |||
OrganizationDto organization = dbTester.organizations().insert(); | |||
ComponentDto component = randomComponent(organization); | |||
IssueDto fromHostSpotIssue = insertNewClosedIssue(component, ruleType, t -> t.setIsFromHotspot(true)); | |||
insertToClosedDiff(fromHostSpotIssue); | |||
IssueDto issue = insertNewClosedIssue(component, ruleType); | |||
IssueChangeDto issueChange = insertToClosedDiff(issue); | |||
RecorderResultHandler resultHandler = new RecorderResultHandler(); | |||
underTest.scrollClosedByComponentUuid(component.uuid(), NO_FILTERING_ON_CLOSE_DATE, resultHandler); | |||
assertThat(resultHandler.issues) | |||
.extracting(IssueDto::getKey, t -> t.getClosedChangeData().get()) | |||
.containsOnly(tuple(issue.getKey(), issueChange.getChangeData())); | |||
} | |||
@Test | |||
@UseDataProvider("closedIssuesSupportedRuleTypes") | |||
public void scrollClosedByComponentUuid_return_one_row_per_status_diff_to_CLOSED_sorted_by_most_recent_creation_date_first(RuleType ruleType) { |
@@ -43,6 +43,7 @@ public class DbVersion81 implements DbVersion { | |||
.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) | |||
.add(3114, "Drop 'In Review' Security Hotspots status ", DropSecurityHotSpotsInReviewStatus.class); | |||
.add(3114, "Drop 'In Review' Security Hotspots status ", DropSecurityHotSpotsInReviewStatus.class) | |||
.add(3115, "Migrate Manual Vulnerabilities to Security Hotspots ", MigrateManualVulnerabilitiesToSecurityHotSpots.class); | |||
} | |||
} |
@@ -0,0 +1,68 @@ | |||
/* | |||
* 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; | |||
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW; | |||
import static org.sonar.api.rules.RuleType.VULNERABILITY; | |||
public class MigrateManualVulnerabilitiesToSecurityHotSpots extends DataChange { | |||
private System2 system; | |||
public MigrateManualVulnerabilitiesToSecurityHotSpots(Database db, System2 system) { | |||
super(db); | |||
this.system = system; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
MassUpdate updateIssues = context.prepareMassUpdate(); | |||
updateIssues.select("select id, kee, project_uuid, component_uuid from issues where from_hotspot = ? and issue_type = ?") | |||
.setBoolean(1, true) | |||
.setInt(2, 3); | |||
updateIssues.update("update issues set issue_type = ?, status = ? where id = ? and from_hotspot = ? and issue_type = ?"); | |||
updateIssues.update("insert into issue_changes(issue_key, change_type, change_data, created_at, updated_at, issue_change_creation_date) " + | |||
"VALUES(?, ?, ?, ?, ?, ?)"); | |||
updateIssues.execute((row, update, updateIndex) -> { | |||
if (updateIndex == 0) { | |||
update.setInt(1, 4) | |||
.setString(2, STATUS_TO_REVIEW) | |||
.setLong(3, row.getLong(1)) | |||
.setBoolean(4, true) | |||
.setInt(5, VULNERABILITY.getDbConstant()); | |||
} else if (updateIndex == 1) { | |||
long currentTime = system.now(); | |||
update.setString(1, row.getString(2)) | |||
.setString(2, "diff") | |||
.setString(3, "type=VULNERABILITY|SECURITY_HOTSPOT,status=OPEN|TO_REVIEW") | |||
.setLong(4, currentTime) | |||
.setLong(5, currentTime) | |||
.setLong(6, currentTime); | |||
} | |||
return true; | |||
}); | |||
} | |||
} |
@@ -36,7 +36,7 @@ public class DbVersion81Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 15); | |||
verifyMigrationCount(underTest, 16); | |||
} | |||
} |
@@ -0,0 +1,140 @@ | |||
/* | |||
* 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.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Random; | |||
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.rules.RuleType.BUG; | |||
import static org.sonar.api.rules.RuleType.CODE_SMELL; | |||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | |||
import static org.sonar.api.rules.RuleType.VULNERABILITY; | |||
public class MigrateManualVulnerabilitiesToSecurityHotSpotsTest { | |||
private final static String ISSUES_TABLE_NAME = "issues"; | |||
private final static int TOTAL_NUMBER_OF_ISSUES = 9; | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(MigrateManualVulnerabilitiesToSecurityHotSpotsTest.class, "schema.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private System2 system2 = System2.INSTANCE; | |||
private DataChange underTest = new MigrateManualVulnerabilitiesToSecurityHotSpots(db.database(), system2); | |||
@Test | |||
public void should_migrate_manual_vulnerabilities_only() throws SQLException { | |||
Random random = new Random(); | |||
List<Integer> range = IntStream.range(0, TOTAL_NUMBER_OF_ISSUES).boxed() | |||
.collect(Collectors.toCollection(ArrayList::new)); | |||
Collections.shuffle(range); | |||
insertIssue(range.get(0), CODE_SMELL.getDbConstant(), random.nextBoolean()); | |||
insertIssue(range.get(1), BUG.getDbConstant(), random.nextBoolean()); | |||
insertIssue(range.get(2), VULNERABILITY.getDbConstant(), false); | |||
insertIssue(range.get(3), SECURITY_HOTSPOT.getDbConstant(), random.nextBoolean()); | |||
insertIssue(range.get(4), -1, random.nextBoolean()); | |||
insertIssue(range.get(5), VULNERABILITY.getDbConstant(), true); | |||
insertIssue(range.get(6), VULNERABILITY.getDbConstant(), true); | |||
insertIssue(range.get(7), VULNERABILITY.getDbConstant(), true); | |||
insertIssue(range.get(8), VULNERABILITY.getDbConstant(), true); | |||
underTest.execute(); | |||
assertIssueNotChanged(range.get(0), CODE_SMELL.getDbConstant()); | |||
assertIssueNotChanged(range.get(1), BUG.getDbConstant()); | |||
assertIssueNotChanged(range.get(2), VULNERABILITY.getDbConstant()); | |||
assertIssueNotChanged(range.get(3), SECURITY_HOTSPOT.getDbConstant()); | |||
assertIssueNotChanged(range.get(4), -1); | |||
assertIssueChanged(range.get(5)); | |||
assertIssueChanged(range.get(6)); | |||
assertIssueChanged(range.get(7)); | |||
assertIssueChanged(range.get(8)); | |||
// 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("type=VULNERABILITY|SECURITY_HOTSPOT,status=OPEN|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, int expectedType) { | |||
List<Map<String, Object>> row = db.select(String.format("select issue_type, status from issues where kee = '%s'", "issue-key-" + issueId)); | |||
assertThat(row).hasSize(1); | |||
Map<String, Object> issueData = row.get(0); | |||
assertThat(issueData.get("STATUS")) | |||
.isNull(); | |||
assertThat(issueData.get("ISSUE_TYPE")) | |||
.isEqualTo(expectedType); | |||
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, int issueType, boolean fromHotspot) { | |||
db.executeInsert(ISSUES_TABLE_NAME, | |||
"kee", "issue-key-" + issueId, | |||
"issue_type", issueType, | |||
"from_hotspot", fromHotspot, | |||
"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"); |
@@ -1,36 +0,0 @@ | |||
/* | |||
* 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.issue.workflow; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.core.issue.DefaultIssue; | |||
/** | |||
* The vulnerability originally come from a hotspot that was moved to vulnerability by a security auditor. | |||
*/ | |||
enum IsManualVulnerability implements Condition { | |||
INSTANCE; | |||
@Override | |||
public boolean matches(Issue issue) { | |||
return ((DefaultIssue) issue).type() == RuleType.VULNERABILITY && ((DefaultIssue) issue).isFromHotspot(); | |||
} | |||
} |
@@ -23,11 +23,11 @@ import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.core.issue.DefaultIssue; | |||
enum IsNotHotspotNorManualVulnerability implements Condition { | |||
enum IsNotHotspot implements Condition { | |||
INSTANCE; | |||
@Override | |||
public boolean matches(Issue issue) { | |||
return ((DefaultIssue) issue).type() != RuleType.SECURITY_HOTSPOT && !((DefaultIssue) issue).isFromHotspot(); | |||
return ((DefaultIssue) issue).type() != RuleType.SECURITY_HOTSPOT; | |||
} | |||
} |
@@ -75,31 +75,31 @@ public class IssueWorkflow implements Startable { | |||
// confirm | |||
.transition(Transition.builder(DefaultTransitions.CONFIRM) | |||
.from(STATUS_OPEN).to(STATUS_CONFIRMED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(null)) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.CONFIRM) | |||
.from(STATUS_REOPENED).to(STATUS_CONFIRMED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(null)) | |||
.build()) | |||
// resolve as fixed | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE) | |||
.from(STATUS_OPEN).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE) | |||
.from(STATUS_REOPENED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESOLVE) | |||
.from(STATUS_CONFIRMED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
@@ -107,31 +107,31 @@ public class IssueWorkflow implements Startable { | |||
// reopen | |||
.transition(Transition.builder(DefaultTransitions.UNCONFIRM) | |||
.from(STATUS_CONFIRMED).to(STATUS_REOPENED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(null)) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.REOPEN) | |||
.from(STATUS_RESOLVED).to(STATUS_REOPENED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(null)) | |||
.build()) | |||
// resolve as false-positive | |||
.transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) | |||
.from(STATUS_OPEN).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) | |||
.from(STATUS_REOPENED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.FALSE_POSITIVE) | |||
.from(STATUS_CONFIRMED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_FALSE_POSITIVE), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
@@ -139,19 +139,19 @@ public class IssueWorkflow implements Startable { | |||
// resolve as won't fix | |||
.transition(Transition.builder(DefaultTransitions.WONT_FIX) | |||
.from(STATUS_OPEN).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.WONT_FIX) | |||
.from(STATUS_REOPENED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.WONT_FIX) | |||
.from(STATUS_CONFIRMED).to(STATUS_RESOLVED) | |||
.conditions(IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(RESOLUTION_WONT_FIX), UnsetAssignee.INSTANCE) | |||
.requiredProjectPermission(UserRole.ISSUE_ADMIN) | |||
.build()); | |||
@@ -165,39 +165,13 @@ public class IssueWorkflow implements Startable { | |||
.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) | |||
.functions(new SetType(RuleType.SECURITY_HOTSPOT), new SetResolution(RESOLUTION_FIXED)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.OPEN_AS_VULNERABILITY) | |||
.from(STATUS_REVIEWED).to(STATUS_OPEN) | |||
.conditions(new HasType(RuleType.SECURITY_HOTSPOT)) | |||
.functions(new SetResolution(null), 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)) | |||
.functions(new SetType(RuleType.VULNERABILITY)) | |||
.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)) | |||
.functions(new SetResolution(null)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
.transition(Transition.builder(DefaultTransitions.RESET_AS_TO_REVIEW) | |||
.from(STATUS_OPEN).to(STATUS_TO_REVIEW) | |||
.conditions(new HasType(RuleType.VULNERABILITY), IsManualVulnerability.INSTANCE) | |||
.functions(new SetType(RuleType.SECURITY_HOTSPOT), new SetResolution(null)) | |||
.requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN) | |||
.build()) | |||
; | |||
.build()); | |||
} | |||
private static void buildAutomaticTransitions(StateMachine.Builder builder) { | |||
@@ -243,7 +217,7 @@ public class IssueWorkflow implements Startable { | |||
// Reopen issues that are marked as resolved but that are still alive. | |||
.transition(Transition.builder("automaticreopen") | |||
.from(STATUS_RESOLVED).to(STATUS_REOPENED) | |||
.conditions(new NotCondition(IsBeingClosed.INSTANCE), new HasResolution(RESOLUTION_FIXED), IsNotHotspotNorManualVulnerability.INSTANCE) | |||
.conditions(new NotCondition(IsBeingClosed.INSTANCE), new HasResolution(RESOLUTION_FIXED), IsNotHotspot.INSTANCE) | |||
.functions(new SetResolution(null), UnsetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
@@ -253,7 +227,7 @@ public class IssueWorkflow implements Startable { | |||
.conditions( | |||
new PreviousStatusWas(STATUS_OPEN), | |||
new HasResolution(RESOLUTION_REMOVED, RESOLUTION_FIXED), | |||
IsNotHotspotNorManualVulnerability.INSTANCE) | |||
IsNotHotspot.INSTANCE) | |||
.functions(RestoreResolutionFunction.INSTANCE, UnsetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
@@ -262,7 +236,7 @@ public class IssueWorkflow implements Startable { | |||
.conditions( | |||
new PreviousStatusWas(STATUS_REOPENED), | |||
new HasResolution(RESOLUTION_REMOVED, RESOLUTION_FIXED), | |||
IsNotHotspotNorManualVulnerability.INSTANCE) | |||
IsNotHotspot.INSTANCE) | |||
.functions(RestoreResolutionFunction.INSTANCE, UnsetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
@@ -271,7 +245,7 @@ public class IssueWorkflow implements Startable { | |||
.conditions( | |||
new PreviousStatusWas(STATUS_CONFIRMED), | |||
new HasResolution(RESOLUTION_REMOVED, RESOLUTION_FIXED), | |||
IsNotHotspotNorManualVulnerability.INSTANCE) | |||
IsNotHotspot.INSTANCE) | |||
.functions(RestoreResolutionFunction.INSTANCE, UnsetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()) | |||
@@ -280,7 +254,7 @@ public class IssueWorkflow implements Startable { | |||
.conditions( | |||
new PreviousStatusWas(STATUS_RESOLVED), | |||
new HasResolution(RESOLUTION_REMOVED, RESOLUTION_FIXED), | |||
IsNotHotspotNorManualVulnerability.INSTANCE) | |||
IsNotHotspot.INSTANCE) | |||
.functions(RestoreResolutionFunction.INSTANCE, UnsetCloseDate.INSTANCE) | |||
.automatic() | |||
.build()); |
@@ -31,7 +31,6 @@ import org.apache.commons.lang.time.DateUtils; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.api.issue.DefaultTransitions; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.core.issue.DefaultIssue; | |||
@@ -44,7 +43,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_OPEN; | |||
import static org.sonar.api.issue.Issue.STATUS_RESOLVED; | |||
import static org.sonar.api.issue.Issue.STATUS_REVIEWED; | |||
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW; | |||
@@ -93,7 +91,7 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
List<Transition> transitions = underTest.outTransitions(issue); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed", "openasvulnerability"); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed"); | |||
} | |||
@Test | |||
@@ -103,17 +101,7 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
List<Transition> transitions = underTest.outTransitions(issue); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("openasvulnerability", "resetastoreview"); | |||
} | |||
@Test | |||
public void list_out_vulnerability_transitions_in_status_open() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue().setType(RuleType.VULNERABILITY).setResolution(RESOLUTION_FIXED).setStatus(STATUS_OPEN).setIsFromHotspot(true); | |||
List<Transition> transitions = underTest.outTransitions(issue); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resolveasreviewed", "resetastoreview"); | |||
assertThat(keys(transitions)).containsExactlyInAnyOrder("resetastoreview"); | |||
} | |||
@Test | |||
@@ -121,7 +109,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_TO_REVIEW); | |||
boolean result = underTest.doManualTransition(issue, DefaultTransitions.RESOLVE_AS_REVIEWED, IssueChangeContext.createUser(new Date(), "USER1")); | |||
@@ -131,46 +118,11 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.resolution()).isEqualTo(RESOLUTION_FIXED); | |||
} | |||
@Test | |||
public void open_as_vulnerability_from_to_review() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_TO_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_reviewed() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setResolution(RESOLUTION_FIXED) | |||
.setStatus(STATUS_REVIEWED); | |||
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 reset_as_to_review_from_reviewed() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.SECURITY_HOTSPOT) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_REVIEWED) | |||
.setResolution(RESOLUTION_FIXED); | |||
@@ -181,22 +133,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
public void reset_as_to_review_from_opened_as_vulnerability() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.VULNERABILITY) | |||
.setIsFromHotspot(true) | |||
.setStatus(STATUS_OPEN) | |||
.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 automatically_close_resolved_security_hotspots_in_status_to_review() { | |||
underTest.start(); | |||
@@ -235,26 +171,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND)); | |||
} | |||
@Test | |||
public void automatically_close_hotspots_opened_as_vulnerability() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setType(RuleType.VULNERABILITY) | |||
.setResolution(null) | |||
.setStatus(STATUS_OPEN) | |||
.setIsFromHotspot(true) | |||
.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 | |||
@UseDataProvider("allStatusesLeadingToClosed") | |||
public void do_not_automatically_reopen_closed_issues_of_security_hotspots(String previousStatus) { | |||
@@ -292,43 +208,6 @@ public class IssueWorkflowForSecurityHotspotsTest { | |||
assertThat(issue.resolution()).isNull(); | |||
} | |||
@Test | |||
@UseDataProvider("allStatusesLeadingToClosed") | |||
public void do_not_automatically_reopen_closed_issues_of_manual_vulnerability(String previousStatus) { | |||
DefaultIssue[] issues = Arrays.stream(SUPPORTED_RESOLUTIONS_FOR_UNCLOSING) | |||
.map(resolution -> { | |||
DefaultIssue issue = newClosedIssue(resolution); | |||
setStatusPreviousToClosed(issue, previousStatus); | |||
issue.setIsFromHotspot(true); | |||
return issue; | |||
}) | |||
.toArray(DefaultIssue[]::new); | |||
Date now = new Date(); | |||
underTest.start(); | |||
Arrays.stream(issues).forEach(issue -> { | |||
underTest.doAutomaticTransition(issue, IssueChangeContext.createScan(now)); | |||
assertThat(issue.status()).isEqualTo(STATUS_CLOSED); | |||
assertThat(issue.updateDate()).isNull(); | |||
}); | |||
} | |||
@Test | |||
public void do_not_allow_to_doManualTransition_when_condition_fails() { | |||
underTest.start(); | |||
DefaultIssue issue = new DefaultIssue() | |||
.setKey("ABCDE") | |||
// Detect is only available on hotspot | |||
.setType(RuleType.VULNERABILITY) | |||
.setIsFromHotspot(false) | |||
.setStatus(STATUS_OPEN) | |||
.setResolution(null) | |||
.setRuleKey(XOO_X1); | |||
assertThat(underTest.doManualTransition(issue, DefaultTransitions.RESET_AS_TO_REVIEW, IssueChangeContext.createScan(new Date()))).isFalse(); | |||
} | |||
private Collection<String> keys(List<Transition> transitions) { | |||
return transitions.stream().map(Transition::key).collect(MoreCollectors.toList()); | |||
} |
@@ -22,10 +22,10 @@ package org.sonar.server.issue; | |||
import java.util.Collection; | |||
import java.util.Map; | |||
import org.sonar.api.issue.Issue; | |||
import org.sonar.server.issue.workflow.IsUnResolved; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.web.UserRole; | |||
import org.sonar.core.issue.DefaultIssue; | |||
import org.sonar.server.issue.workflow.IsUnResolved; | |||
import org.sonar.server.user.UserSession; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
@@ -47,7 +47,7 @@ public class SetTypeAction extends Action { | |||
} | |||
private boolean isCurrentUserIssueAdmin(Issue issue) { | |||
return !((DefaultIssue) issue).isFromHotspot() && userSession.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, issue.projectUuid()); | |||
return userSession.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, issue.projectUuid()); | |||
} | |||
@Override |
@@ -80,7 +80,9 @@ import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
import static java.util.function.Function.identity; | |||
import static java.util.stream.Collectors.toMap; | |||
import static org.sonar.api.issue.DefaultTransitions.OPEN_AS_VULNERABILITY; | |||
import static org.sonar.api.issue.DefaultTransitions.REOPEN; | |||
import static org.sonar.api.issue.DefaultTransitions.SET_AS_IN_REVIEW; | |||
import static org.sonar.api.rule.Severity.BLOCKER; | |||
import static org.sonar.api.rules.RuleType.BUG; | |||
import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; | |||
@@ -143,6 +145,8 @@ public class BulkChangeAction implements IssuesWsAction { | |||
"Requires authentication.") | |||
.setSince("3.7") | |||
.setChangelog( | |||
new Change("8.1", OPEN_AS_VULNERABILITY + " transition is no more supported"), | |||
new Change("8.1", SET_AS_IN_REVIEW + " transition is no more supported"), | |||
new Change("6.3", "'actions' parameter is ignored")) | |||
.setHandler(this) | |||
.setResponseExample(getClass().getResource("bulk_change-example.json")) |
@@ -75,7 +75,8 @@ 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("8.1", OPEN_AS_VULNERABILITY + " transition is no more supported"), | |||
new Change("8.1", SET_AS_IN_REVIEW + " transition is no more supported"), | |||
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"), |
@@ -199,6 +199,7 @@ public class SearchAction implements IssuesWsAction, Startable { | |||
PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS) | |||
.setSince("3.6") | |||
.setChangelog( | |||
new Change("8.1", "response field 'fromHotspot' has been deprecated and is no more populated"), | |||
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"), |
@@ -188,7 +188,6 @@ public class SearchResponseFormat { | |||
if (dto.isExternal()) { | |||
issueBuilder.setExternalRuleEngine(engineNameFrom(dto.getRuleKey())); | |||
} | |||
issueBuilder.setFromHotspot(dto.isFromHotspot()); | |||
if (dto.getType() != RuleType.SECURITY_HOTSPOT.getDbConstant()) { | |||
issueBuilder.setSeverity(Common.Severity.valueOf(dto.getSeverity())); | |||
} |
@@ -234,10 +234,8 @@ public class SearchResponseLoader { | |||
} | |||
availableActions.add(ASSIGN_KEY); | |||
availableActions.add("set_tags"); | |||
if (!issue.isFromHotspot() && userSession.hasComponentPermission(ISSUE_ADMIN, project)) { | |||
if (ruleType != RuleType.SECURITY_HOTSPOT && userSession.hasComponentPermission(ISSUE_ADMIN, project)) { | |||
availableActions.add(SET_TYPE_KEY); | |||
} | |||
if ((ruleType != RuleType.SECURITY_HOTSPOT && userSession.hasComponentPermission(ISSUE_ADMIN, project))) { | |||
availableActions.add(SET_SEVERITY_KEY); | |||
} | |||
return availableActions; |
@@ -37,6 +37,7 @@ import org.sonar.server.issue.IssueFieldsSetter; | |||
import org.sonar.server.issue.IssueFinder; | |||
import org.sonar.server.user.UserSession; | |||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | |||
import static org.sonar.api.web.UserRole.ISSUE_ADMIN; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SET_TYPE; | |||
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUE; | |||
@@ -105,9 +106,11 @@ public class SetTypeAction implements IssuesWsAction { | |||
private SearchResponseData setType(DbSession session, String issueKey, RuleType ruleType) { | |||
IssueDto issueDto = issueFinder.getByKey(session, issueKey); | |||
DefaultIssue issue = issueDto.toDefaultIssue(); | |||
if (issue.isFromHotspot()) { | |||
if (SECURITY_HOTSPOT == issue.type()) { | |||
throw new IllegalArgumentException("Changing type of a security hotspot is not permitted"); | |||
} | |||
userSession.checkComponentUuidPermission(ISSUE_ADMIN, issue.projectUuid()); | |||
IssueChangeContext context = IssueChangeContext.createUser(new Date(system2.now()), userSession.getUuid()); |
@@ -19,12 +19,21 @@ | |||
*/ | |||
package org.sonar.server.issue.ws; | |||
import com.google.common.collect.Sets; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.EnumSet; | |||
import java.util.List; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.rules.RuleType; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
@@ -65,13 +74,14 @@ import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.api.rules.RuleType.BUG; | |||
import static org.sonar.api.rules.RuleType.CODE_SMELL; | |||
import static org.sonar.api.rules.RuleType.VULNERABILITY; | |||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | |||
import static org.sonar.api.web.UserRole.ISSUE_ADMIN; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.issue.IssueTesting.newDto; | |||
import static org.sonar.db.rule.RuleTesting.newRuleDto; | |||
@RunWith(DataProviderRunner.class) | |||
public class SetTypeActionTest { | |||
@Rule | |||
@@ -102,34 +112,28 @@ public class SetTypeActionTest { | |||
responseWriter, system2)); | |||
@Test | |||
public void set_type() { | |||
@UseDataProvider("allTypesFromToExceptHotspots") | |||
public void set_type(RuleType from, RuleType to) { | |||
long now = 1_999_777_234L; | |||
when(system2.now()).thenReturn(now); | |||
IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(CODE_SMELL)); | |||
IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(from)); | |||
setUserWithBrowseAndAdministerIssuePermission(issueDto); | |||
call(issueDto.getKey(), BUG.name()); | |||
call(issueDto.getKey(), to.name()); | |||
verify(responseWriter).write(eq(issueDto.getKey()), preloadedSearchResponseDataCaptor.capture(), any(Request.class), any(Response.class)); | |||
verifyContentOfPreloadedSearchResponseData(issueDto); | |||
IssueDto issueReloaded = dbClient.issueDao().selectByKey(dbTester.getSession(), issueDto.getKey()).get(); | |||
assertThat(issueReloaded.getType()).isEqualTo(BUG.getDbConstant()); | |||
assertThat(issueReloaded.getType()).isEqualTo(to.getDbConstant()); | |||
assertThat(issueChangePostProcessor.calledComponents()) | |||
.extracting(ComponentDto::uuid) | |||
.containsExactlyInAnyOrder(issueDto.getComponentUuid()); | |||
} | |||
@Test | |||
public void prevent_changing_type_security_hotspot() { | |||
long now = 1_999_777_234L; | |||
when(system2.now()).thenReturn(now); | |||
IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(VULNERABILITY).setIsFromHotspot(true)); | |||
setUserWithBrowseAndAdministerIssuePermission(issueDto); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Changing type of a security hotspot is not permitted"); | |||
call(issueDto.getKey(), BUG.name()); | |||
if (from != to) { | |||
verifyContentOfPreloadedSearchResponseData(issueDto); | |||
assertThat(issueChangePostProcessor.calledComponents()) | |||
.extracting(ComponentDto::uuid) | |||
.containsExactlyInAnyOrder(issueDto.getComponentUuid()); | |||
} else { | |||
assertThat(issueChangePostProcessor.wasCalled()) | |||
.isFalse(); | |||
} | |||
} | |||
@Test | |||
@@ -174,12 +178,25 @@ public class SetTypeActionTest { | |||
} | |||
@Test | |||
public void fail_when_missing_administer_issue_permission() { | |||
IssueDto issueDto = issueDbTester.insertIssue(); | |||
@UseDataProvider("allTypesExceptSecurityHotspot") | |||
public void fail_type_except_hotspot_when_missing_administer_issue_permission(RuleType type) { | |||
IssueDto issueDto = issueDbTester.insertIssue(issue -> issue.setType(type)); | |||
logInAndAddProjectPermission("john", issueDto, USER); | |||
expectedException.expect(ForbiddenException.class); | |||
call(issueDto.getKey(), BUG.name()); | |||
call(issueDto.getKey(), type.name()); | |||
} | |||
@Test | |||
@UseDataProvider("allTypesExceptSecurityHotspot") | |||
public void fail_if_trying_to_change_type_of_a_hotspot(RuleType type) { | |||
long now = 1_999_777_234L; | |||
when(system2.now()).thenReturn(now); | |||
IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(SECURITY_HOTSPOT)); | |||
setUserWithBrowseAndAdministerIssuePermission(issueDto); | |||
expectedException.expect(IllegalArgumentException.class); | |||
call(issueDto.getKey(), type.name()); | |||
} | |||
@Test | |||
@@ -229,4 +246,25 @@ public class SetTypeActionTest { | |||
.extracting(ComponentDto::uuid) | |||
.containsOnly(issue.getComponentUuid(), issue.getProjectUuid()); | |||
} | |||
@DataProvider | |||
public static Object[][] allTypesExceptSecurityHotspot() { | |||
return EnumSet.allOf(RuleType.class) | |||
.stream() | |||
.filter(ruleType -> SECURITY_HOTSPOT != ruleType) | |||
.map(t -> new Object[] {t}) | |||
.toArray(Object[][]::new); | |||
} | |||
@DataProvider | |||
public static Object[][] allTypesFromToExceptHotspots() { | |||
Set<RuleType> set = EnumSet.allOf(RuleType.class) | |||
.stream() | |||
.filter(ruleType -> SECURITY_HOTSPOT != ruleType) | |||
.collect(Collectors.toSet()); | |||
return Sets.cartesianProduct(set, set) | |||
.stream() | |||
.map(ruleTypes -> new Object[] {ruleTypes.get(0), ruleTypes.get(1)}) | |||
.toArray(Object[][]::new); | |||
} | |||
} |
@@ -89,8 +89,6 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. | |||
private Date updateDate; | |||
private Date closeDate; | |||
private boolean isFromHotspot = false; | |||
// Current changes | |||
private FieldDiffs currentChange = null; | |||
@@ -607,15 +605,6 @@ public class DefaultIssue implements Issue, Trackable, org.sonar.api.ce.measure. | |||
} | |||
} | |||
public DefaultIssue setIsFromHotspot(boolean value) { | |||
this.isFromHotspot = value; | |||
return this; | |||
} | |||
public boolean isFromHotspot() { | |||
return isFromHotspot; | |||
} | |||
public DefaultIssue setTags(Collection<String> tags) { | |||
this.tags = new LinkedHashSet<>(tags); | |||
return this; |
@@ -53,7 +53,9 @@ public interface DefaultTransitions { | |||
/** | |||
* @since 7.8 | |||
* @deprecated since 8.1, security hotspots can no longer be converted to vulnerabilities | |||
*/ | |||
@Deprecated | |||
String OPEN_AS_VULNERABILITY = "openasvulnerability"; | |||
/** | |||
@@ -65,5 +67,5 @@ public interface DefaultTransitions { | |||
* @since 4.4 | |||
*/ | |||
List<String> ALL = unmodifiableList(asList(CONFIRM, UNCONFIRM, REOPEN, RESOLVE, FALSE_POSITIVE, WONT_FIX, CLOSE, | |||
SET_AS_IN_REVIEW, RESOLVE_AS_REVIEWED, OPEN_AS_VULNERABILITY,RESET_AS_TO_REVIEW)); | |||
SET_AS_IN_REVIEW, RESOLVE_AS_REVIEWED, RESET_AS_TO_REVIEW)); | |||
} |