diff options
author | Zipeng WU <zipeng.wu@sonarsource.com> | 2021-10-20 18:41:34 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-10-22 20:03:28 +0000 |
commit | 2b665b2a21166eba85647d42f841eb0adb589b51 (patch) | |
tree | 2dee588e9b734ac6dbb4bb6482d971ee46178b00 | |
parent | de160ea89db1173a8aad783f3405cfa8eb040629 (diff) | |
download | sonarqube-2b665b2a21166eba85647d42f841eb0adb589b51.tar.gz sonarqube-2b665b2a21166eba85647d42f841eb0adb589b51.zip |
SONAR-15440 Add permission delegate in ListAction
8 files changed, 93 insertions, 21 deletions
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java index fd2178c771e..dab5673e874 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ListAction.java @@ -69,11 +69,11 @@ public class ListAction implements QualityGatesWsAction { try (DbSession dbSession = dbClient.openSession(false)) { QualityGateDto defaultQualityGate = finder.getDefault(dbSession); Collection<QualityGateDto> qualityGates = dbClient.qualityGateDao().selectAll(dbSession); - writeProtobuf(buildResponse(qualityGates, defaultQualityGate), request, response); + writeProtobuf(buildResponse(dbSession, qualityGates, defaultQualityGate), request, response); } } - private ListWsResponse buildResponse(Collection<QualityGateDto> qualityGates, @Nullable QualityGateDto defaultQualityGate) { + private ListWsResponse buildResponse(DbSession dbSession, Collection<QualityGateDto> qualityGates, @Nullable QualityGateDto defaultQualityGate) { String defaultUuid = defaultQualityGate == null ? null : defaultQualityGate.getUuid(); ListWsResponse.Builder builder = ListWsResponse.newBuilder() .setActions(ListWsResponse.RootActions.newBuilder().setCreate(wsSupport.isQualityGateAdmin())) @@ -83,7 +83,7 @@ public class ListAction implements QualityGatesWsAction { .setName(qualityGate.getName()) .setIsDefault(qualityGate.getUuid().equals(defaultUuid)) .setIsBuiltIn(qualityGate.isBuiltIn()) - .setActions(wsSupport.getActions(qualityGate, defaultQualityGate)) + .setActions(wsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) .build()) .collect(toList())); ofNullable(defaultUuid).ifPresent(builder::setDefault); diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java index a958f63c638..05077faf567 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsSupport.java @@ -67,17 +67,19 @@ public class QualityGatesWsSupport { return userSession.hasPermission(ADMINISTER_QUALITY_GATES); } - Qualitygates.Actions getActions(QualityGateDto qualityGate, @Nullable QualityGateDto defaultQualityGate) { + Qualitygates.Actions getActions(DbSession dbSession, QualityGateDto qualityGate, @Nullable QualityGateDto defaultQualityGate) { boolean isDefault = defaultQualityGate != null && Objects.equals(defaultQualityGate.getUuid(), qualityGate.getUuid()); boolean isBuiltIn = qualityGate.isBuiltIn(); boolean isQualityGateAdmin = isQualityGateAdmin(); + boolean canLimitedEdit = isQualityGateAdmin || hasLimitedPermission(dbSession, qualityGate); return Qualitygates.Actions.newBuilder() .setCopy(isQualityGateAdmin) .setRename(!isBuiltIn && isQualityGateAdmin) - .setManageConditions(!isBuiltIn && isQualityGateAdmin) + .setManageConditions(!isBuiltIn && canLimitedEdit) .setDelete(!isDefault && !isBuiltIn && isQualityGateAdmin) .setSetAsDefault(!isDefault && isQualityGateAdmin) .setAssociateProjects(!isDefault && isQualityGateAdmin) + .setDelegate(!isBuiltIn && canLimitedEdit) .build(); } @@ -89,12 +91,15 @@ public class QualityGatesWsSupport { void checkCanLimitedEdit(DbSession dbSession, QualityGateDto qualityGate) { checkNotBuiltIn(qualityGate); if (!userSession.hasPermission(ADMINISTER_QUALITY_GATES) - && !userHasPermission(dbSession, qualityGate) - && !userHasGroupPermission(dbSession, qualityGate)) { + && !hasLimitedPermission(dbSession, qualityGate)) { throw insufficientPrivilegesException(); } } + boolean hasLimitedPermission(DbSession dbSession, QualityGateDto qualityGate) { + return userHasPermission(dbSession, qualityGate) || userHasGroupPermission(dbSession, qualityGate); + } + boolean userHasGroupPermission(DbSession dbSession, QualityGateDto qualityGate) { return userSession.isLoggedIn() && dbClient.qualityGateGroupPermissionsDao().exists(dbSession, qualityGate, userSession.getGroups()); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java index 2cbb7c96db8..db1ba240f02 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java @@ -94,7 +94,7 @@ public class ShowAction implements QualityGatesWsAction { Collection<QualityGateConditionDto> conditions = getConditions(dbSession, qualityGate); Map<String, MetricDto> metricsByUuid = getMetricsByUuid(dbSession, conditions); QualityGateDto defaultQualityGate = qualityGateFinder.getDefault(dbSession); - writeProtobuf(buildResponse(qualityGate, defaultQualityGate, conditions, metricsByUuid), request, response); + writeProtobuf(buildResponse(dbSession, qualityGate, defaultQualityGate, conditions, metricsByUuid), request, response); } } @@ -119,8 +119,8 @@ public class ShowAction implements QualityGatesWsAction { .collect(uniqueIndex(MetricDto::getUuid)); } - private ShowWsResponse buildResponse(QualityGateDto qualityGate, QualityGateDto defaultQualityGate, - Collection<QualityGateConditionDto> conditions, Map<String, MetricDto> metricsByUuid) { + private ShowWsResponse buildResponse(DbSession dbSession, QualityGateDto qualityGate, QualityGateDto defaultQualityGate, + Collection<QualityGateConditionDto> conditions, Map<String, MetricDto> metricsByUuid) { return ShowWsResponse.newBuilder() .setId(qualityGate.getUuid()) .setName(qualityGate.getName()) @@ -128,7 +128,7 @@ public class ShowAction implements QualityGatesWsAction { .addAllConditions(conditions.stream() .map(toWsCondition(metricsByUuid)) .collect(toList())) - .setActions(wsSupport.getActions(qualityGate, defaultQualityGate)) + .setActions(wsSupport.getActions(dbSession, qualityGate, defaultQualityGate)) .build(); } diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json index b9de9b682f4..cd36b8c6e34 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/list-example.json @@ -11,7 +11,8 @@ "copy": true, "associateProjects": false, "delete": false, - "manageConditions": false + "manageConditions": false, + "delegate": false } }, { @@ -25,7 +26,8 @@ "copy": true, "associateProjects": true, "delete": true, - "manageConditions": true + "manageConditions": true, + "delegate": true } } ], diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json index 6883a72566c..99858d38935 100644 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json @@ -22,6 +22,7 @@ "copy": true, "associateProjects": true, "delete": true, - "manageConditions": true + "manageConditions": true, + "delegate": true } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java index 4abffdf987c..8250502410a 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ListActionTest.java @@ -26,6 +26,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.user.UserDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.qualitygate.QualityGateFinder; import org.sonar.server.tester.UserSessionRule; @@ -124,11 +125,37 @@ public class ListActionTest { assertThat(response.getQualitygatesList()) .extracting(QualityGate::getName, qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), - qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects()) + qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), + qp -> qp.getActions().getDelegate()) .containsExactlyInAnyOrder( - tuple(defaultQualityGate.getName(), true, false, true, true, false, false), - tuple(builtInQualityGate.getName(), false, false, false, true, true, true), - tuple(otherQualityGate.getName(), true, true, true, true, true, true)); + tuple(defaultQualityGate.getName(), true, false, true, true, false, false, true), + tuple(builtInQualityGate.getName(), false, false, false, true, true, true, false), + tuple(otherQualityGate.getName(), true, true, true, true, true, true, true)); + } + + @Test + public void actions_with_quality_gate_delegate_permission() { + QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way")); + QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage")); + UserDto user = db.users().insertUser(); + db.qualityGates().addUserPermission(defaultQualityGate, user); + db.qualityGates().addUserPermission(otherQualityGate, user); + userSession.logIn(user); + db.qualityGates().setDefaultQualityGate(defaultQualityGate); + + ListWsResponse response = ws.newRequest().executeProtobuf(ListWsResponse.class); + + assertThat(response.getActions()) + .extracting(ListWsResponse.RootActions::getCreate) + .isEqualTo(false); + assertThat(response.getQualitygatesList()) + .extracting(QualityGate::getName, + qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), + qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), + qp -> qp.getActions().getDelegate()) + .containsExactlyInAnyOrder( + tuple(defaultQualityGate.getName(), false, false, true, false, false, false, true), + tuple(otherQualityGate.getName(), false, false, true, false, false, false, true)); } @Test @@ -146,10 +173,11 @@ public class ListActionTest { assertThat(response.getQualitygatesList()) .extracting(QualityGate::getName, qg -> qg.getActions().getRename(), qg -> qg.getActions().getDelete(), qg -> qg.getActions().getManageConditions(), - qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects()) + qp -> qp.getActions().getCopy(), qp -> qp.getActions().getSetAsDefault(), qp -> qp.getActions().getAssociateProjects(), + qp -> qp.getActions().getDelegate()) .containsExactlyInAnyOrder( - tuple(defaultQualityGate.getName(), false, false, false, false, false, false), - tuple(otherQualityGate.getName(), false, false, false, false, false, false)); + tuple(defaultQualityGate.getName(), false, false, false, false, false, false, false), + tuple(otherQualityGate.getName(), false, false, false, false, false, false, false)); } @Test diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java index 19c8bc2a5ea..de776d5dbe5 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java @@ -29,6 +29,7 @@ import org.sonar.db.DbTester; import org.sonar.db.metric.MetricDto; import org.sonar.db.qualitygate.QualityGateConditionDto; import org.sonar.db.qualitygate.QualityGateDto; +import org.sonar.db.user.UserDto; import org.sonar.server.component.TestComponentFinder; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.qualitygate.QualityGateFinder; @@ -200,6 +201,40 @@ public class ShowActionTest { } @Test + public void actions_when_delegate_quality_gate_administer() { + QualityGateDto defaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way")); + QualityGateDto otherQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("Sonar way - Without Coverage")); + UserDto user = db.users().insertUser(); + db.qualityGates().addUserPermission(defaultQualityGate, user); + db.qualityGates().addUserPermission(otherQualityGate, user); + userSession.logIn(user); + db.qualityGates().setDefaultQualityGate(defaultQualityGate); + + ShowWsResponse response = ws.newRequest() + .setParam("name", defaultQualityGate.getName()) + .executeProtobuf(ShowWsResponse.class); + + assertThat(response.getActions()) + .extracting( + Actions::getRename, Actions::getDelete, Actions::getManageConditions, + Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate) + .containsExactlyInAnyOrder( + false, false, true, false, false, false, true); + + response = ws.newRequest() + .setParam("name", otherQualityGate.getName()) + .executeProtobuf(ShowWsResponse.class); + + assertThat(response.getActions()) + .extracting( + Actions::getRename, Actions::getDelete, Actions::getManageConditions, + Actions::getCopy, Actions::getSetAsDefault, Actions::getAssociateProjects, Actions::getDelegate) + .containsExactlyInAnyOrder( + false, false, true, false, false, false, true); + + } + + @Test public void fail_when_no_name_or_id() { QualityGateDto qualityGate = db.qualityGates().insertQualityGate(); diff --git a/sonar-ws/src/main/protobuf/ws-qualitygates.proto b/sonar-ws/src/main/protobuf/ws-qualitygates.proto index e9aa2946124..e59873e098f 100644 --- a/sonar-ws/src/main/protobuf/ws-qualitygates.proto +++ b/sonar-ws/src/main/protobuf/ws-qualitygates.proto @@ -180,6 +180,7 @@ message Actions { optional bool associateProjects = 4; optional bool delete = 5; optional bool manageConditions = 6; + optional bool delegate = 7; } // WS api/qualitygates/search_users |