]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10887 Create a new permission: Administer Security Hotspots
authorJulien HENRY <julien.henry@sonarsource.com>
Mon, 18 Jun 2018 11:19:01 +0000 (13:19 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 4 Jul 2018 07:31:04 +0000 (09:31 +0200)
19 files changed:
server/sonar-db-dao/src/main/java/org/sonar/core/permission/ProjectPermissions.java
server/sonar-db-dao/src/test/java/org/sonar/core/permission/ProjectPermissionsTest.java
server/sonar-server/src/main/java/org/sonar/server/issue/workflow/IssueWorkflow.java
server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdater.java
server/sonar-server/src/main/java/org/sonar/server/organization/OrganizationUpdaterImpl.java
server/sonar-server/src/main/java/org/sonar/server/startup/RegisterPermissionTemplates.java
server/sonar-server/src/main/resources/org/sonar/server/permission/ws/template/search_templates-example.json
server/sonar-server/src/test/java/org/sonar/server/i18n/I18nRule.java
server/sonar-server/src/test/java/org/sonar/server/organization/OrganizationUpdaterImplTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/GroupPermissionChangerTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/PermissionTemplateServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/UserPermissionChangerTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/SearchTemplatesActionTest.java
server/sonar-server/src/test/java/org/sonar/server/startup/RegisterPermissionTemplatesTest.java
server/sonar-web/src/main/js/apps/permission-templates/utils.js
server/sonar-web/src/main/js/apps/permissions/project/constants.js
sonar-core/src/main/resources/org/sonar/l10n/core.properties
sonar-plugin-api/src/main/java/org/sonar/api/web/UserRole.java

index 04b47d1c1d33775577cc785112183903d6ea8ec7..f797d699e00c5a73a518e75074388337b89f80eb 100644 (file)
@@ -36,9 +36,10 @@ public final class ProjectPermissions {
   public static final Set<String> PUBLIC_PERMISSIONS = ImmutableSet.of(UserRole.USER, UserRole.CODEVIEWER);
 
   /**
-   * All the component permissions values, ordered from {@link UserRole#USER} to {@link GlobalPermissions#SCAN_EXECUTION}.
+   * All the component permissions values
    */
-  public static final List<String> ALL = ImmutableList.of(UserRole.ADMIN, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION, UserRole.USER);
+  public static final List<String> ALL = ImmutableList.of(UserRole.ADMIN, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN,
+    GlobalPermissions.SCAN_EXECUTION, UserRole.USER);
 
   public static final String ALL_ON_ONE_LINE = Joiner.on(", ").join(ProjectPermissions.ALL);
 
index dd86d8d7099456d37234f3325f2dc961dfaaf9e7..d78726c74b2624f008de4c4d217eb54f416ba8f7 100644 (file)
@@ -28,11 +28,11 @@ public class ProjectPermissionsTest {
 
   @Test
   public void all_permissions() {
-    assertThat(ProjectPermissions.ALL).containsExactly(UserRole.ADMIN, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION, UserRole.USER);
+    assertThat(ProjectPermissions.ALL).containsExactly(UserRole.ADMIN, UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION, UserRole.USER);
   }
 
   @Test
   public void all_permissions_as_string() {
-    assertThat(ProjectPermissions.ALL_ON_ONE_LINE).isEqualTo("admin, codeviewer, issueadmin, scan, user");
+    assertThat(ProjectPermissions.ALL_ON_ONE_LINE).isEqualTo("admin, codeviewer, issueadmin, securityhotspotadmin, scan, user");
   }
 }
index aec49fbf75e37147d3132d8b83002b78b4554e10..d2a3bf1c671873376541ebb17aa342ceb86a4216 100644 (file)
@@ -147,25 +147,25 @@ public class IssueWorkflow implements Startable {
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_OPEN)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT))
         .functions(new SetType(RuleType.VULNERABILITY))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.DETECT)
         .from(Issue.STATUS_REOPENED).to(Issue.STATUS_OPEN)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT))
         .functions(new SetType(RuleType.VULNERABILITY))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.DETECT)
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_OPEN)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT), new HasResolution(Issue.RESOLUTION_WONT_FIX))
         .functions(new SetType(RuleType.VULNERABILITY), new SetResolution(null))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.DISMISS)
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_REOPENED)
         .conditions(IsManualVulnerability.INSTANCE)
         .functions(new SetType(RuleType.SECURITY_HOTSPOT))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.REQUEST_REVIEW)
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED)
@@ -181,31 +181,31 @@ public class IssueWorkflow implements Startable {
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_REOPENED)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT), new HasResolution(Issue.RESOLUTION_FIXED))
         .functions(new SetType(RuleType.VULNERABILITY), new SetResolution(null))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.ACCEPT)
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_RESOLVED)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT), new HasResolution(Issue.RESOLUTION_FIXED))
         .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.CLEAR)
         .from(Issue.STATUS_OPEN).to(Issue.STATUS_RESOLVED)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT))
         .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.CLEAR)
         .from(Issue.STATUS_REOPENED).to(Issue.STATUS_RESOLVED)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT))
         .functions(new SetResolution(Issue.RESOLUTION_WONT_FIX))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build())
       .transition(Transition.builder(DefaultTransitions.REOPEN_HOTSPOT)
         .from(Issue.STATUS_RESOLVED).to(Issue.STATUS_REOPENED)
         .conditions(new HasType(RuleType.SECURITY_HOTSPOT), new HasResolution(Issue.RESOLUTION_WONT_FIX))
         .functions(new SetResolution(null))
-        .requiredProjectPermission(UserRole.ISSUE_ADMIN) // TODO need to check new permission
+        .requiredProjectPermission(UserRole.SECURITYHOTSPOT_ADMIN)
         .build());
 
   }
index 5748e200790edfd80cdacccc34653b37e251fbcc..60bb5006439ce5609159f9d38f35e11608a2102a 100644 (file)
@@ -58,6 +58,7 @@ public interface OrganizationUpdater {
    *     <ul>
    *       <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#ADMIN ADMIN}</li>
    *       <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#ISSUE_ADMIN ISSUE_ADMIN}</li>
+   *       <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link UserRole#SECURITYHOTSPOT_ADMIN SECURITYHOTSPOT_ADMIN}</li>
    *       <li>group {@link #OWNERS_GROUP_NAME Owners} : {@link GlobalPermissions#SCAN_EXECUTION SCAN_EXECUTION}</li>
    *       <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#USER USER}</li>
    *       <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#CODEVIEWER CODEVIEWER}</li>
@@ -102,6 +103,7 @@ public interface OrganizationUpdater {
    *     <ul>
    *       <li>project creator : {@link UserRole#ADMIN ADMIN}</li>
    *       <li>project creator : {@link UserRole#ISSUE_ADMIN ISSUE_ADMIN}</li>
+   *       <li>project creator : {@link UserRole#SECURITYHOTSPOT_ADMIN SECURITYHOTSPOT_ADMIN}</li>
    *       <li>project creator : {@link GlobalPermissions#SCAN_EXECUTION SCAN_EXECUTION}</li>
    *       <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#USER USER}</li>
    *       <li>group {@link DefaultGroupCreatorImpl#DEFAULT_GROUP_NAME members} : {@link UserRole#CODEVIEWER CODEVIEWER}</li>
index 7d7f756c18eb3d3165c35d27d3c30cfb005db539..3d9b20dfe521455876f12a4ce91ab64cf4275f94 100644 (file)
@@ -59,6 +59,7 @@ import static java.util.Objects.requireNonNull;
 import static org.sonar.api.web.UserRole.ADMIN;
 import static org.sonar.api.web.UserRole.CODEVIEWER;
 import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.SECURITYHOTSPOT_ADMIN;
 import static org.sonar.api.web.UserRole.USER;
 import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
 import static org.sonar.db.permission.OrganizationPermission.SCAN;
@@ -229,6 +230,7 @@ public class OrganizationUpdaterImpl implements OrganizationUpdater {
 
     insertGroupPermission(dbSession, permissionTemplateDto, ADMIN, ownerGroup);
     insertGroupPermission(dbSession, permissionTemplateDto, ISSUE_ADMIN, ownerGroup);
+    insertGroupPermission(dbSession, permissionTemplateDto, SECURITYHOTSPOT_ADMIN, ownerGroup);
     insertGroupPermission(dbSession, permissionTemplateDto, SCAN.getKey(), ownerGroup);
     insertGroupPermission(dbSession, permissionTemplateDto, USER, defaultGroup);
     insertGroupPermission(dbSession, permissionTemplateDto, CODEVIEWER, defaultGroup);
@@ -254,6 +256,7 @@ public class OrganizationUpdaterImpl implements OrganizationUpdater {
 
     insertProjectCreatorPermission(dbSession, permissionTemplateDto, ADMIN, now);
     insertProjectCreatorPermission(dbSession, permissionTemplateDto, ISSUE_ADMIN, now);
+    insertProjectCreatorPermission(dbSession, permissionTemplateDto, SECURITYHOTSPOT_ADMIN, now);
     insertProjectCreatorPermission(dbSession, permissionTemplateDto, SCAN.getKey(), now);
     insertGroupPermission(dbSession, permissionTemplateDto, USER, defaultGroup);
     insertGroupPermission(dbSession, permissionTemplateDto, CODEVIEWER, defaultGroup);
index 7cb69d01ce72979bb712ac0dfd3556bc414c819a..045eda15b6eb395d7056b2e6e5d335f1cf1efcc2 100644 (file)
@@ -94,6 +94,7 @@ public class RegisterPermissionTemplates {
     if (admins.isPresent()) {
       insertGroupPermission(dbSession, template, UserRole.ADMIN, admins.get());
       insertGroupPermission(dbSession, template, UserRole.ISSUE_ADMIN, admins.get());
+      insertGroupPermission(dbSession, template, UserRole.SECURITYHOTSPOT_ADMIN, admins.get());
     } else {
       LOG.error("Cannot setup default permission for group: " + DefaultGroups.ADMINISTRATORS);
     }
index 643c7bf91119aad4df909feacb81e3ea66f2181a..b5f0d50a8e18452a4676d509ad0531cfa3901068 100644 (file)
           "groupsCount": 0,
           "withProjectCreator": false
         },
+        {
+          "key": "securityhotspotadmin",
+          "usersCount": 0,
+          "groupsCount": 0,
+          "withProjectCreator": false
+        },
         {
           "key": "scan",
           "usersCount": 0,
           "groupsCount": 3,
           "withProjectCreator": false
         },
+        {
+          "key": "securityhotspotadmin",
+          "usersCount": 0,
+          "groupsCount": 0,
+          "withProjectCreator": false
+        },
         {
           "key": "scan",
           "usersCount": 0,
index 07e117034e27061ac9c481798c139849655a230b..e1a4892607ca76edd6614aa650080819922699cf 100644 (file)
@@ -60,6 +60,8 @@ public class I18nRule implements TestRule, I18n {
     put("projects_role.issueadmin", "Administer Issues");
     put("projects_role.issueadmin.desc", "Grants the permission to perform advanced editing on issues: marking an issue " +
       "False Positive / Won't Fix or changing an Issue's severity. (Users will also need \"Browse\" permission)");
+    put("projects_role.securityhotspotadmin", "Administer Security Hotspots");
+    put("projects_role.securityhotspotadmin.desc", "Detect a Vulnerability from a \"Security Hotspot\". Reject, clear, accept, reopen a \"Security Hotspot\" (users also need \"Browse\" permissions).");
     put("projects_role.user", "Browse");
     put("projects_role.user.desc", "Ability to access a project, browse its measures, and create/edit issues for it.");
     put("projects_role.codeviewer", "See Source Code");
index 9e08bc95ebda1857b2bebcaa861be9d1fdf60977..be832a90a8d81dfd63c166637a87fe4e7b87ebf6 100644 (file)
@@ -267,7 +267,7 @@ public class OrganizationUpdaterImplTest {
     assertThat(dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, defaultTemplate.getId()))
       .extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission)
       .containsOnly(
-        tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION),
+        tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), UserRole.SECURITYHOTSPOT_ADMIN), tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION),
         tuple(defaultGroupId, UserRole.USER), tuple(defaultGroupId, UserRole.CODEVIEWER));
   }
 
@@ -445,7 +445,7 @@ public class OrganizationUpdaterImplTest {
     assertThat(dbClient.permissionTemplateCharacteristicDao().selectByTemplateIds(dbSession, Collections.singletonList(defaultTemplate.getId())))
       .extracting(PermissionTemplateCharacteristicDto::getWithProjectCreator, PermissionTemplateCharacteristicDto::getPermission)
       .containsOnly(
-        tuple(true, UserRole.ADMIN), tuple(true, UserRole.ISSUE_ADMIN), tuple(true, GlobalPermissions.SCAN_EXECUTION));
+        tuple(true, UserRole.ADMIN), tuple(true, UserRole.ISSUE_ADMIN), tuple(true, UserRole.SECURITYHOTSPOT_ADMIN), tuple(true, GlobalPermissions.SCAN_EXECUTION));
   }
 
   @Test
index 01af1c6d535c2158c4c85c27586dd8ef70d57f9a..076d906a9fa23b2823b5405c7f7fd7583cdd3a6c 100644 (file)
@@ -362,7 +362,7 @@ public class CreateActionTest {
     assertThat(dbClient.permissionTemplateDao().selectGroupPermissionsByTemplateId(dbSession, defaultTemplate.getId()))
       .extracting(PermissionTemplateGroupDto::getGroupId, PermissionTemplateGroupDto::getPermission)
       .containsOnly(
-        tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION),
+        tuple(ownersGroup.getId(), UserRole.ADMIN), tuple(ownersGroup.getId(), UserRole.ISSUE_ADMIN), tuple(ownersGroup.getId(), UserRole.SECURITYHOTSPOT_ADMIN), tuple(ownersGroup.getId(), GlobalPermissions.SCAN_EXECUTION),
         tuple(defaultGroup.getId(), UserRole.USER), tuple(defaultGroup.getId(), UserRole.CODEVIEWER));
   }
 
index b9406c5eb1e00eec2d46bf5e11a91e0f1b89ce13..54ae041674ce75349965e18b19ef6be3f8853ed3 100644 (file)
@@ -321,7 +321,7 @@ public class GroupPermissionChangerTest {
           apply(new GroupPermissionChange(PermissionChange.Operation.ADD, perm, new ProjectId(privateProject), groupId));
           fail("a BadRequestException should have been thrown for permission " + perm);
         } catch (BadRequestException e) {
-          assertThat(e).hasMessage("Invalid project permission '" + perm + "'. Valid values are [admin, codeviewer, issueadmin, scan, user]");
+          assertThat(e).hasMessage("Invalid project permission '" + perm + "'. Valid values are [admin, codeviewer, issueadmin, securityhotspotadmin, scan, user]");
         }
       });
   }
@@ -338,7 +338,7 @@ public class GroupPermissionChangerTest {
           apply(new GroupPermissionChange(PermissionChange.Operation.ADD, perm, new ProjectId(publicProject), groupId));
           fail("a BadRequestException should have been thrown for permission " + perm);
         } catch (BadRequestException e) {
-          assertThat(e).hasMessage("Invalid project permission '" + perm + "'. Valid values are [admin, codeviewer, issueadmin, scan, user]");
+          assertThat(e).hasMessage("Invalid project permission '" + perm + "'. Valid values are [admin, codeviewer, issueadmin, securityhotspotadmin, scan, user]");
         }
       });
   }
index 4805954e0e5caa2266aca552a3aa235fadef2f5e..9c55b543b397c4919438ec3ab99a3af3292b2b01 100644 (file)
@@ -102,7 +102,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject));
 
     assertThat(selectProjectPermissionsOfGroup(organization, null, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -118,7 +118,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), publicProject, null);
 
     assertThat(selectProjectPermissionsOfGroup(organization, null, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -134,7 +134,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyAndCommit(session, permissionTemplate, singletonList(privateProject));
 
     assertThat(selectProjectPermissionsOfGroup(organization, group, privateProject))
-      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -151,7 +151,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), privateProject, null);
 
     assertThat(selectProjectPermissionsOfGroup(organization, group, privateProject))
-      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -167,7 +167,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject));
 
     assertThat(selectProjectPermissionsOfGroup(organization, group, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -184,7 +184,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), publicProject, null);
 
     assertThat(selectProjectPermissionsOfGroup(organization, group, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -200,7 +200,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyAndCommit(session, permissionTemplate, singletonList(publicProject));
 
     assertThat(selectProjectPermissionsOfUser(user, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -217,7 +217,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), publicProject, null);
 
     assertThat(selectProjectPermissionsOfUser(user, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -233,7 +233,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyAndCommit(session, permissionTemplate, singletonList(privateProject));
 
     assertThat(selectProjectPermissionsOfUser(user, privateProject))
-      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -250,7 +250,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), privateProject, null);
 
     assertThat(selectProjectPermissionsOfUser(user, privateProject))
-      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -267,7 +267,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), publicProject, user.getId());
 
     assertThat(selectProjectPermissionsOfUser(user, publicProject))
-      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
@@ -284,7 +284,7 @@ public class PermissionTemplateServiceTest {
     underTest.applyDefault(session, organization.getUuid(), privateProject, user.getId());
 
     assertThat(selectProjectPermissionsOfUser(user, privateProject))
-      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, GlobalPermissions.SCAN_EXECUTION);
+      .containsOnly("p1", UserRole.USER, UserRole.CODEVIEWER, UserRole.ADMIN, UserRole.ISSUE_ADMIN, UserRole.SECURITYHOTSPOT_ADMIN, GlobalPermissions.SCAN_EXECUTION);
   }
 
   @Test
index 10621035974d8ce64903bf81bc918298859a84b2..0bdff5b6434c4fe4354bfd2d66a5e69cd572fb64 100644 (file)
@@ -251,7 +251,7 @@ public class UserPermissionChangerTest {
   @Test
   public void fail_to_add_global_permission_on_project() {
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Invalid project permission 'gateadmin'. Valid values are [admin, codeviewer, issueadmin, scan, user]");
+    expectedException.expectMessage("Invalid project permission 'gateadmin'. Valid values are [admin, codeviewer, issueadmin, securityhotspotadmin, scan, user]");
 
     UserPermissionChange change = new UserPermissionChange(ADD, org1.getUuid(), QUALITY_GATE_ADMIN, new ProjectId(privateProject), UserId.from(user1));
     apply(change);
index 1d7d77f15e257de41883727cd58153480e1de3a6..98f70e4e0385a15888b910c33ffd69fdca3b22f2 100644 (file)
@@ -224,6 +224,11 @@ public class SearchTemplatesActionTest extends BasePermissionWsTest<SearchTempla
           +
           "    }," +
           "    {" +
+          "      \"key\": \"securityhotspotadmin\"," +
+          "      \"name\": \"Administer Security Hotspots\"," +
+          "      \"description\": \"Detect a Vulnerability from a \\\"Security Hotspot\\\". Reject, clear, accept, reopen a \\\"Security Hotspot\\\" (users also need \\\"Browse\\\" permissions).\"" +
+          "    }," +
+          "    {" +
           "      \"key\": \"scan\"," +
           "      \"name\": \"Execute Analysis\"," +
           "      \"description\": \"Ability to execute analyses, and to get all settings required to perform the analysis, even the secured ones like the scm account password, the jira account password, and so on.\""
index 179d92e3d39219744199979261515c92a1391863..31acf69393de3f06239d251a6b6d56b7e09ab499 100644 (file)
@@ -83,9 +83,10 @@ public class RegisterPermissionTemplatesTest {
     assertThat(defaultTemplate.getName()).isEqualTo("Default template");
 
     List<PermissionTemplateGroupDto> groupPermissions = selectGroupPermissions(defaultTemplate);
-    assertThat(groupPermissions).hasSize(4);
+    assertThat(groupPermissions).hasSize(5);
     expectGroupPermission(groupPermissions, UserRole.ADMIN, DefaultGroups.ADMINISTRATORS);
     expectGroupPermission(groupPermissions, UserRole.ISSUE_ADMIN, DefaultGroups.ADMINISTRATORS);
+    expectGroupPermission(groupPermissions, UserRole.SECURITYHOTSPOT_ADMIN, DefaultGroups.ADMINISTRATORS);
     expectGroupPermission(groupPermissions, UserRole.CODEVIEWER, defaultGroup.getName());
     expectGroupPermission(groupPermissions, UserRole.USER, defaultGroup.getName());
 
index a5bcb8aca3d2036fb8bdb31cedea2f511b528eff..e7afc8ed47e4cee5abc789910e5d9984e14b2fc2 100644 (file)
  */
 import { sortBy } from 'lodash';
 
-export const PERMISSIONS_ORDER = ['user', 'codeviewer', 'issueadmin', 'admin', 'scan'];
+export const PERMISSIONS_ORDER = [
+  'user',
+  'codeviewer',
+  'issueadmin',
+  'securityhotspotadmin',
+  'admin',
+  'scan'
+];
 
 /**
  * Sort list of permissions based on predefined order
index ad87e07029d39742d5d21a530c8e6fd0ee6cb014..13a6bee92c56e74ec23f0088ff3d183f2ff364be 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-export const PERMISSIONS_ORDER_FOR_PROJECT = ['user', 'codeviewer', 'issueadmin', 'admin', 'scan'];
+export const PERMISSIONS_ORDER_FOR_PROJECT = [
+  'user',
+  'codeviewer',
+  'issueadmin',
+  'securityhotspotadmin',
+  'admin',
+  'scan'
+];
 
 export const PERMISSIONS_ORDER_FOR_VIEW = ['user', 'admin'];
 
index 60d21398eedb9acf6b9e32a2a9872c5d6aea65cd..5717d41eaf9610d5e7d2bb0c5f2995e30532dc04 100644 (file)
@@ -2024,6 +2024,8 @@ projects_role.admin=Administer
 projects_role.admin.desc=Access project settings and perform administration tasks. (Users will also need "Browse" permission)
 projects_role.issueadmin=Administer Issues
 projects_role.issueadmin.desc=Change the type and severity of issues, resolve issues as being "won't fix" or "false-positive" (users also need "Browse" permission).
+projects_role.securityhotspotadmin=Administer Security Hotspots
+projects_role.securityhotspotadmin.desc=Detect a Vulnerability from a "Security Hotspot". Reject, clear, accept, reopen a "Security Hotspot" (users also need "Browse" permissions).
 projects_role.user=Browse
 projects_role.user.desc=Access a project, browse its measures and issues, confirm or resolve issues as "fixed", change the assignee, comment on issues and change tags.
 projects_role.codeviewer=See Source Code
index c768712a333a2f5a703e626112da68ceda4e47ca..196218cdc514a8bce9c5065c66b142923713be06 100644 (file)
@@ -42,6 +42,11 @@ public @interface UserRole {
   String CODEVIEWER = "codeviewer";
   String ISSUE_ADMIN = "issueadmin";
 
+  /**
+   * @since 7.3
+   */
+  String SECURITYHOTSPOT_ADMIN = "securityhotspotadmin";
+
   String[] value() default {};
 
 }