From 2983446f9fd681aa50b963ec83e31c4422276d18 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 6 Jan 2020 11:23:04 +0100 Subject: [PATCH] SONAR-12753 add canChangeStatus to api/hotspots/show response --- .../server/hotspot/ws/HotspotWsSupport.java | 5 + .../sonar/server/hotspot/ws/ShowAction.java | 1 + .../sonar/server/hotspot/ws/show-example.json | 3 +- .../server/hotspot/ws/ShowActionTest.java | 123 +++++++++++++++++- sonar-ws/src/main/protobuf/ws-hotspots.proto | 1 + 5 files changed, 131 insertions(+), 2 deletions(-) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsSupport.java index 30ea1243303..31c1f5ed430 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/HotspotWsSupport.java @@ -23,6 +23,7 @@ import java.util.Date; import org.sonar.api.issue.Issue; import org.sonar.api.rules.RuleType; import org.sonar.api.utils.System2; +import org.sonar.api.web.UserRole; import org.sonar.core.issue.IssueChangeContext; import org.sonar.db.DbClient; import org.sonar.db.DbSession; @@ -67,6 +68,10 @@ public class HotspotWsSupport { return project; } + boolean canChangeStatus(ComponentDto project) { + return userSession.hasComponentPermission(UserRole.SECURITYHOTSPOT_ADMIN, project); + } + IssueChangeContext newIssueChangeContext() { return IssueChangeContext.createUser(new Date(system2.now()), checkLoggedIn()); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java index 262499adf32..faaa13a0ac5 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/ShowAction.java @@ -151,6 +151,7 @@ public class ShowAction implements HotspotsWsAction { responseBuilder .setProject(responseFormatter.formatComponent(Hotspots.Component.newBuilder(), components.getProject())) .setComponent(responseFormatter.formatComponent(Hotspots.Component.newBuilder(), components.getComponent())); + responseBuilder.setCanChangeStatus(hotspotWsSupport.canChangeStatus(components.getProject())); } private void formatRule(ShowWsResponse.Builder responseBuilder, RuleDefinitionDto ruleDefinitionDto) { diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/hotspot/ws/show-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/hotspot/ws/show-example.json index 613bae9642f..f43ea76a03c 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/hotspot/ws/show-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/hotspot/ws/show-example.json @@ -101,5 +101,6 @@ "name": "Joe", "active": true } - ] + ], + "canChangeStatus": true } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java index 9b0f6beb0d0..49232dd91cc 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/ShowActionTest.java @@ -219,6 +219,126 @@ public class ShowActionTest { assertThat(response.getKey()).isEqualTo(hotspot.getKey()); } + @Test + public void return_canChangeStatus_false_on_public_project_when_anonymous() { + ComponentDto project = dbTester.components().insertPublicProject(); + userSessionRule.registerComponents(project); + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file); + mockChangelogAndCommentsFormattingContext(); + + Hotspots.ShowWsResponse response = newRequest(hotspot) + .executeProtobuf(Hotspots.ShowWsResponse.class); + + assertThat(response.getCanChangeStatus()).isFalse(); + } + + @Test + @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN") + public void return_canChangeStatus_false_on_public_project_when_authenticated_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) { + ComponentDto project = dbTester.components().insertPublicProject(); + userSessionRule.logIn().registerComponents(project); + if (permission != null) { + userSessionRule.addProjectPermission(permission, project); + } + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file); + mockChangelogAndCommentsFormattingContext(); + + Hotspots.ShowWsResponse response = newRequest(hotspot) + .executeProtobuf(Hotspots.ShowWsResponse.class); + + assertThat(response.getCanChangeStatus()).isFalse(); + } + + @Test + @UseDataProvider("allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN") + public void return_canChangeStatus_true_on_public_project_when_authenticated_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) { + ComponentDto project = dbTester.components().insertPublicProject(); + userSessionRule.registerComponents(project) + .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project); + if (permission != null) { + userSessionRule.addProjectPermission(permission, project); + } + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file); + mockChangelogAndCommentsFormattingContext(); + + Hotspots.ShowWsResponse response = newRequest(hotspot) + .executeProtobuf(Hotspots.ShowWsResponse.class); + + assertThat(response.getCanChangeStatus()).isTrue(); + } + + @DataProvider + public static Object[][] allPublicProjectPermissionsButSECURITYHOTSPOT_ADMIN() { + return new Object[][] { + {null}, // no permission + {UserRole.ADMIN}, + {UserRole.SCAN}, + {UserRole.ISSUE_ADMIN} + }; + } + + @Test + @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER") + public void return_canChangeStatus_false_on_private_project_without_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) { + ComponentDto project = dbTester.components().insertPrivateProject(); + userSessionRule + .registerComponents(project) + .logIn() + .addProjectPermission(UserRole.USER, project); + if (permission != null) { + userSessionRule.addProjectPermission(permission, project); + } + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file); + mockChangelogAndCommentsFormattingContext(); + + Hotspots.ShowWsResponse response = newRequest(hotspot) + .executeProtobuf(Hotspots.ShowWsResponse.class); + + assertThat(response.getCanChangeStatus()).isFalse(); + } + + @Test + @UseDataProvider("allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER") + public void return_canChangeStatus_false_on_private_project_with_SECURITYHOTSPOT_ADMIN_permission(@Nullable String permission) { + ComponentDto project = dbTester.components().insertPrivateProject(); + userSessionRule + .registerComponents(project) + .logIn() + .addProjectPermission(UserRole.USER, project) + .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project); + if (permission != null) { + userSessionRule.addProjectPermission(permission, project); + } + ComponentDto file = dbTester.components().insertComponent(newFileDto(project)); + RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT); + IssueDto hotspot = dbTester.issues().insertHotspot(rule, project, file); + mockChangelogAndCommentsFormattingContext(); + + Hotspots.ShowWsResponse response = newRequest(hotspot) + .executeProtobuf(Hotspots.ShowWsResponse.class); + + assertThat(response.getCanChangeStatus()).isTrue(); + } + + @DataProvider + public static Object[][] allPrivateProjectPermissionsButSECURITYHOTSPOT_ADMIN_and_USER() { + return new Object[][] { + {null}, // only USER permission + {UserRole.CODEVIEWER}, + {UserRole.ADMIN}, + {UserRole.SCAN}, + {UserRole.ISSUE_ADMIN} + }; + } + @Test @UseDataProvider("statusAndResolutionCombinations") public void returns_status_and_resolution(String status, @Nullable String resolution) { @@ -706,7 +826,8 @@ public class ShowActionTest { .setName("test-project") .setLongName("test-project") .setDbKey("com.sonarsource:test-project")); - userSessionRule.registerComponents(project); + userSessionRule.registerComponents(project) + .addProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN, project); ComponentDto file = dbTester.components().insertComponent( newFileDto(project) diff --git a/sonar-ws/src/main/protobuf/ws-hotspots.proto b/sonar-ws/src/main/protobuf/ws-hotspots.proto index 2a4c53025e1..40e6fb62af6 100644 --- a/sonar-ws/src/main/protobuf/ws-hotspots.proto +++ b/sonar-ws/src/main/protobuf/ws-hotspots.proto @@ -67,6 +67,7 @@ message ShowWsResponse { repeated sonarqube.ws.commons.Changelog changelog = 14; repeated sonarqube.ws.commons.Comment comment = 15; repeated sonarqube.ws.commons.User users = 16; + optional bool canChangeStatus = 17; } message Component { -- 2.39.5