Quellcode durchsuchen

SONAR-20578 Add GithubPermissionsMappingService to core-extension-github-provisioning

tags/10.3.0.82913
Aurelien Poscia vor 8 Monaten
Ursprung
Commit
ea684ddb27

+ 0
- 309
server/sonar-webserver-common/src/it/java/org/sonar/server/common/github/permissions/GithubPermissionsMappingServiceIT.java Datei anzeigen

@@ -1,309 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.common.github.permissions;

import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.core.util.SequenceUuidFactory;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.provisioning.GithubPermissionsMappingDao;
import org.sonar.db.provisioning.GithubPermissionsMappingDto;
import org.sonar.server.common.permission.Operation;
import org.sonar.server.exceptions.NotFoundException;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.ADMIN_GITHUB_ROLE;
import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.MAINTAIN_GITHUB_ROLE;
import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.READ_GITHUB_ROLE;
import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.TRIAGE_GITHUB_ROLE;
import static org.sonar.server.common.github.permissions.GithubPermissionsMappingService.WRITE_GITHUB_ROLE;

public class GithubPermissionsMappingServiceIT {

private static final String CUSTOM_ROLE_NAME = "customRole1";

private static final SonarqubePermissions NO_SQ_PERMISSIONS = new SonarqubePermissions(false, false, false, false, false, false);

@Rule
public DbTester db = DbTester.create();
private final DbSession dbSession = db.getSession();

private final AuditPersister auditPersister = mock();
private final GithubPermissionsMappingDao githubPermissionsMappingDao = new GithubPermissionsMappingDao(auditPersister);

private final UuidFactory uuidFactory = new SequenceUuidFactory();

private final GithubPermissionsMappingService underTest = new GithubPermissionsMappingService(db.getDbClient(), githubPermissionsMappingDao, uuidFactory);

@Test
public void getPermissionsMapping_whenMappingNotDefined_returnMappingEntirelyFalse() {
List<GithubPermissionsMapping> actualPermissionsMapping = underTest.getPermissionsMapping();

List<GithubPermissionsMapping> expectedPermissionsMapping = List.of(
new GithubPermissionsMapping(READ_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(WRITE_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS));

assertThat(actualPermissionsMapping).containsAll(expectedPermissionsMapping);
}

@Test
public void getPermissionsMapping_whenMappingDefined_returnMapping() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
CUSTOM_ROLE_NAME, Set.of("user"),
READ_GITHUB_ROLE, Set.of("user", "codeviewer"),
WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

List<GithubPermissionsMapping> actualPermissionsMapping = underTest.getPermissionsMapping();

List<GithubPermissionsMapping> expectedPermissionsMapping = List.of(
new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, new SonarqubePermissions(true, false, false, false, false, false)),
new GithubPermissionsMapping(READ_GITHUB_ROLE, true, new SonarqubePermissions(true, true, false, false, false, false)),
new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(WRITE_GITHUB_ROLE, true, new SonarqubePermissions(true, true, true, true, true, true)),
new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS));

assertThat(actualPermissionsMapping).containsAll(expectedPermissionsMapping);
}

private void persistGithubPermissionsMapping(Map<String, Set<String>> githubRolesToSonarqubePermissions) {
for (Map.Entry<String, Set<String>> githubRoleToSonarqubePermissions : githubRolesToSonarqubePermissions.entrySet()) {
String githubRole = githubRoleToSonarqubePermissions.getKey();
githubRoleToSonarqubePermissions.getValue()
.forEach(permission -> githubPermissionsMappingDao.insert(
dbSession,
new GithubPermissionsMappingDto("uuid_" + githubRole + "_" + permission, githubRole, permission)));
}
dbSession.commit();
}

@Test
public void updatePermissionsMappings_onBaseRole_shouldAddAndRemovePermissions() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(READ_GITHUB_ROLE, Set.of("user", "codeviewer"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "issueadmin", Operation.ADD);
PermissionMappingChange permToAdd2 = new PermissionMappingChange(READ_GITHUB_ROLE, "scan", Operation.ADD);
PermissionMappingChange permToRemove1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.REMOVE);
PermissionMappingChange permToRemove2 = new PermissionMappingChange(READ_GITHUB_ROLE, "codeviewer", Operation.REMOVE);

underTest.updatePermissionsMappings(Set.of(permToAdd1, permToAdd2, permToRemove1, permToRemove2));

GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);

SonarqubePermissions expectedSqPermissions = new SonarqubePermissions(false, false, true, false, false, true);
GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, true, expectedSqPermissions);
assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void updatePermissionsMappings_onCustomRole_shouldAddAndRemovePermissions() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(CUSTOM_ROLE_NAME, Set.of("user", "codeviewer"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

PermissionMappingChange permToAdd1 = new PermissionMappingChange(CUSTOM_ROLE_NAME, "issueadmin", Operation.ADD);
PermissionMappingChange permToRemove1 = new PermissionMappingChange(CUSTOM_ROLE_NAME, "user", Operation.REMOVE);

underTest.updatePermissionsMappings(Set.of(permToAdd1, permToRemove1));

GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(CUSTOM_ROLE_NAME);

SonarqubePermissions expectedSqPermissions = new SonarqubePermissions(false, true, true, false, false, false);
GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, expectedSqPermissions);
assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void updatePermissionsMappings_whenRemovingNonExistingPermission_isNoOp() {
PermissionMappingChange permToRemove1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.REMOVE);

underTest.updatePermissionsMappings(Set.of(permToRemove1));

GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);

GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, true, NO_SQ_PERMISSIONS);
assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void updatePermissionsMappings_whenAddingAlreadyExistingPermission_isNoOp() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(READ_GITHUB_ROLE, Set.of("user", "codeviewer"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);
PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.ADD);

underTest.updatePermissionsMappings(Set.of(permToAdd1));

GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);

SonarqubePermissions expectedSqPermissions = new SonarqubePermissions(true, true, false, false, false, false);
GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, true, expectedSqPermissions);
assertThat(updatedPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void updatePermissionsMappings_handlesUpdatesForDifferentRoles() {
PermissionMappingChange permToAdd1 = new PermissionMappingChange(READ_GITHUB_ROLE, "user", Operation.ADD);
PermissionMappingChange permToAdd2 = new PermissionMappingChange(WRITE_GITHUB_ROLE, "user", Operation.ADD);

underTest.updatePermissionsMappings(Set.of(permToAdd1, permToAdd2));

SonarqubePermissions userOnlySqPermission = new SonarqubePermissions(true, false, false, false, false, false);

GithubPermissionsMapping updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);
assertThat(updatedPermissionsMapping).isEqualTo(new GithubPermissionsMapping(READ_GITHUB_ROLE, true, userOnlySqPermission));

updatedPermissionsMapping = underTest.getPermissionsMappingForGithubRole(WRITE_GITHUB_ROLE);
assertThat(updatedPermissionsMapping).isEqualTo(new GithubPermissionsMapping(WRITE_GITHUB_ROLE, true, userOnlySqPermission));
}

@Test
public void getPermissionsMappingForGithubRole_onBaseRole_shouldReturnMappingOnlyForRole() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
READ_GITHUB_ROLE, Set.of("user", "codeviewer"),
WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

GithubPermissionsMapping actualPermissionsMapping = underTest.getPermissionsMappingForGithubRole(READ_GITHUB_ROLE);

SonarqubePermissions expectedSqPermissions = new SonarqubePermissions(true, true, false, false, false, false);
GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(READ_GITHUB_ROLE, true, expectedSqPermissions);

assertThat(actualPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void getPermissionsMappingForGithubRole_onCustomRole_shouldReturnMappingOnlyForRole() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
CUSTOM_ROLE_NAME, Set.of("admin"),
WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

GithubPermissionsMapping actualPermissionsMapping = underTest.getPermissionsMappingForGithubRole(CUSTOM_ROLE_NAME);

SonarqubePermissions expectedSqPermissions = new SonarqubePermissions(false, false, false, false, true, false);
GithubPermissionsMapping expectedPermissionsMapping = new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, expectedSqPermissions);

assertThat(actualPermissionsMapping).isEqualTo(expectedPermissionsMapping);
}

@Test
public void deletePermissionMappings_whenTryingToDeleteForBaseRole_shouldThrow() {
assertThatThrownBy(() -> underTest.deletePermissionMappings(READ_GITHUB_ROLE))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Deleting permission mapping for GitHub base role '" + READ_GITHUB_ROLE + "' is not allowed.");
}

@Test
public void deletePermissionMappings_whenNoMappingsExistForGithubRole_shouldThrow() {
assertThatThrownBy(() -> underTest.deletePermissionMappings(CUSTOM_ROLE_NAME))
.isInstanceOf(NotFoundException.class)
.hasMessage("Role '" + CUSTOM_ROLE_NAME + "' not found.");
}

@Test
public void deletePermissionMappings_whenTryingToDeleteForCustomRole_shouldDeleteMapping() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(
READ_GITHUB_ROLE, Set.of("user", "codeviewer"),
WRITE_GITHUB_ROLE, Set.of("user", "codeviewer", "issueadmin", "securityhotspotadmin", "admin", "scan"),
CUSTOM_ROLE_NAME, Set.of("user", "codeviewer", "scan"),
"customRole2", Set.of("user", "codeviewer"));

persistGithubPermissionsMapping(githubRolesToSqPermissions);
underTest.deletePermissionMappings("customRole2");

List<GithubPermissionsMapping> allPermissionMappings = underTest.getPermissionsMapping();

assertThat(allPermissionMappings)
.containsExactlyInAnyOrder(
new GithubPermissionsMapping(READ_GITHUB_ROLE, true, new SonarqubePermissions(true, true, false, false, false, false)),
new GithubPermissionsMapping(WRITE_GITHUB_ROLE, true, new SonarqubePermissions(true, true, true, true, true, true)),
new GithubPermissionsMapping(TRIAGE_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(MAINTAIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(ADMIN_GITHUB_ROLE, true, NO_SQ_PERMISSIONS),
new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, new SonarqubePermissions(true, true, false, false, false, true)));
}

@Test
public void createPermissionMapping_whenRoleExists_shouldThrow() {
Map<String, Set<String>> githubRolesToSqPermissions = Map.of(CUSTOM_ROLE_NAME, Set.of("user", "codeviewer"));
persistGithubPermissionsMapping(githubRolesToSqPermissions);

GithubPermissionsMapping request = new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, new SonarqubePermissions(true, true, true, true, true, true));
assertThatThrownBy(() -> underTest.createPermissionMapping(request))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(format("Role %s already exists, it can't be created again.", CUSTOM_ROLE_NAME));
}

@Test
public void createPermissionMapping_whenRoleNameConflictsWithBaseRole_shouldThrow() {
assertBaseRoleConflict("read");
assertBaseRoleConflict("Read");
assertBaseRoleConflict("READ");
}

private void assertBaseRoleConflict(String role) {
GithubPermissionsMapping request = new GithubPermissionsMapping(role, false, new SonarqubePermissions(true, true, true, true, true, true));
assertThatThrownBy(() -> underTest.createPermissionMapping(request))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(format("Role %s can conflicts with a GitHub base role, please chose another name.", role));
}

@Test
public void createPermissionMapping_whenNoPermissions_shouldThrow() {
GithubPermissionsMapping request = new GithubPermissionsMapping(CUSTOM_ROLE_NAME, false, new SonarqubePermissions(false, false, false, false, false, false));
assertThatThrownBy(() -> underTest.createPermissionMapping(request))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(format("Role %s has no permission set, please set at least one permission.", CUSTOM_ROLE_NAME));
}

@Test
public void createPermissionMapping_whenValidRequests_shouldCreateMapping() {
GithubPermissionsMapping role1 = new GithubPermissionsMapping("role1", false, new SonarqubePermissions(false, false, false, false, false, true));
GithubPermissionsMapping role2 = new GithubPermissionsMapping("role2", false, new SonarqubePermissions(false, false, false, false, true, true));
GithubPermissionsMapping role3 = new GithubPermissionsMapping("role3", false, new SonarqubePermissions(false, false, false, true, true, true));
GithubPermissionsMapping role4 = new GithubPermissionsMapping("role4", false, new SonarqubePermissions(false, false, true, true, true, true));
GithubPermissionsMapping role5 = new GithubPermissionsMapping("role5", false, new SonarqubePermissions(false, true, true, true, true, true));
GithubPermissionsMapping role6 = new GithubPermissionsMapping("role6", false, new SonarqubePermissions(true, true, true, true, true, true));

underTest.createPermissionMapping(role1);
underTest.createPermissionMapping(role2);
underTest.createPermissionMapping(role3);
underTest.createPermissionMapping(role4);
underTest.createPermissionMapping(role5);
underTest.createPermissionMapping(role6);

assertThat(underTest.getPermissionsMapping())
.contains(role1, role2, role3, role4, role5, role6);
}

}

+ 0
- 23
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/GithubPermissionsMapping.java Datei anzeigen

@@ -1,23 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.common.github.permissions;

public record GithubPermissionsMapping(String githubRole, boolean isBaseRole, SonarqubePermissions permissions) {
}

+ 0
- 223
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/GithubPermissionsMappingService.java Datei anzeigen

@@ -1,223 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.common.github.permissions;

import com.google.common.collect.Sets;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import org.sonar.api.web.UserRole;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.provisioning.GithubPermissionsMappingDao;
import org.sonar.db.provisioning.GithubPermissionsMappingDto;
import org.sonar.server.exceptions.NotFoundException;

import static java.lang.String.format;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;
import static org.sonar.api.utils.Preconditions.checkArgument;
import static org.sonar.server.common.permission.Operation.ADD;
import static org.sonar.server.common.permission.Operation.REMOVE;

public class GithubPermissionsMappingService {
public static final String READ_GITHUB_ROLE = "read";
public static final String TRIAGE_GITHUB_ROLE = "triage";
public static final String WRITE_GITHUB_ROLE = "write";
public static final String MAINTAIN_GITHUB_ROLE = "maintain";
public static final String ADMIN_GITHUB_ROLE = "admin";

private static final Set<String> GITHUB_BASE_ROLES = Set.of(
READ_GITHUB_ROLE,
TRIAGE_GITHUB_ROLE,
WRITE_GITHUB_ROLE,
MAINTAIN_GITHUB_ROLE,
ADMIN_GITHUB_ROLE);

private static final Map<String, Consumer<SonarqubePermissions.Builder>> permissionAsStringToSonarqubePermission = Map.of(
UserRole.USER, builder -> builder.user(true),
UserRole.CODEVIEWER, builder -> builder.codeViewer(true),
UserRole.ISSUE_ADMIN, builder -> builder.issueAdmin(true),
UserRole.SECURITYHOTSPOT_ADMIN, builder -> builder.securityHotspotAdmin(true),
UserRole.ADMIN, builder -> builder.admin(true),
UserRole.SCAN, builder -> builder.scan(true));

private final DbClient dbClient;
private final GithubPermissionsMappingDao githubPermissionsMappingDao;
private final UuidFactory uuidFactory;

public GithubPermissionsMappingService(DbClient dbClient, GithubPermissionsMappingDao githubPermissionsMappingDao, UuidFactory uuidFactory) {
this.dbClient = dbClient;
this.githubPermissionsMappingDao = githubPermissionsMappingDao;
this.uuidFactory = uuidFactory;
}

public GithubPermissionsMapping getPermissionsMappingForGithubRole(String githubRole) {
try (DbSession dbSession = dbClient.openSession(false)) {
Set<GithubPermissionsMappingDto> permissionsMappingForGithubRole = getPermissionsMappingForGithubRole(dbSession, githubRole);
return toGithubPermissionsMapping(permissionsMappingForGithubRole, githubRole);
}
}

public List<GithubPermissionsMapping> getPermissionsMapping() {
try (DbSession dbSession = dbClient.openSession(false)) {
return toGithubPermissionsMappings(githubPermissionsMappingDao.findAll(dbSession));
}
}

private static List<GithubPermissionsMapping> toGithubPermissionsMappings(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos) {
Map<String, Set<GithubPermissionsMappingDto>> githubRoleToGithubPermissionsMappingDto = githubPermissionsMappingDtos.stream()
.collect(groupingBy(GithubPermissionsMappingDto::githubRole, toSet()));

Set<String> allRoles = Sets.union(GITHUB_BASE_ROLES, githubRoleToGithubPermissionsMappingDto.keySet());
return allRoles.stream()
.map(githubRole -> toGithubPermissionsMapping(githubRoleToGithubPermissionsMappingDto.getOrDefault(githubRole, Set.of()), githubRole))
.toList();
}

private static GithubPermissionsMapping toGithubPermissionsMapping(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos, String githubRole) {
boolean isBaseRole = GITHUB_BASE_ROLES.contains(githubRole);
SonarqubePermissions sonarqubePermissions = getSonarqubePermissions(githubPermissionsMappingDtos);
return new GithubPermissionsMapping(githubRole, isBaseRole, sonarqubePermissions);
}

public void updatePermissionsMappings(Set<PermissionMappingChange> permissionChanges) {
try (DbSession dbSession = dbClient.openSession(false)) {
Map<String, List<PermissionMappingChange>> githubRolesToChanges = permissionChanges.stream()
.collect(groupingBy(PermissionMappingChange::githubRole));
githubRolesToChanges.forEach((githubRole, changes) -> updatePermissionsMappings(dbSession, githubRole, changes));
dbSession.commit();
}
}

public void deletePermissionMappings(String githubRole) {
checkArgument(!GITHUB_BASE_ROLES.contains(githubRole), "Deleting permission mapping for GitHub base role '" + githubRole + "' is not allowed.");
try (DbSession dbSession = dbClient.openSession(false)) {
Set<GithubPermissionsMappingDto> existingPermissions = githubPermissionsMappingDao.findAllForGithubRole(dbSession, githubRole);
if (existingPermissions.isEmpty()) {
throw new NotFoundException("Role '" + githubRole + "' not found.");
}
githubPermissionsMappingDao.deleteAllPermissionsForRole(dbSession, githubRole);
dbSession.commit();
}
}

private void updatePermissionsMappings(DbSession dbSession, String githubRole, List<PermissionMappingChange> permissionChanges) {
Set<String> currentPermissionsForRole = getSqPermissionsForGithubRole(dbSession, githubRole);
removePermissions(dbSession, permissionChanges, currentPermissionsForRole);
addPermissions(dbSession, permissionChanges, currentPermissionsForRole);
}

private Set<String> getSqPermissionsForGithubRole(DbSession dbSession, String githubRole) {
return getPermissionsMappingForGithubRole(dbSession, githubRole).stream()
.map(GithubPermissionsMappingDto::sonarqubePermission)
.collect(toSet());
}

private Set<GithubPermissionsMappingDto> getPermissionsMappingForGithubRole(DbSession dbSession, String githubRole) {
return githubPermissionsMappingDao.findAllForGithubRole(dbSession, githubRole);
}

private void removePermissions(DbSession dbSession, List<PermissionMappingChange> permissionChanges, Set<String> currentPermissionsForRole) {
permissionChanges.stream()
.filter(permissionMappingChange -> REMOVE.equals(permissionMappingChange.operation()))
.filter(permissionMappingChange -> currentPermissionsForRole.contains(permissionMappingChange.sonarqubePermission()))
.forEach(mapping -> githubPermissionsMappingDao.delete(dbSession, mapping.githubRole(), mapping.sonarqubePermission()));
}

private void addPermissions(DbSession dbSession, List<PermissionMappingChange> permissionChanges, Set<String> currentPermissionsForRole) {
permissionChanges.stream()
.filter(permissionMappingChange -> ADD.equals(permissionMappingChange.operation()))
.filter(permissionMappingChange -> !currentPermissionsForRole.contains(permissionMappingChange.sonarqubePermission()))
.forEach(
mapping -> githubPermissionsMappingDao.insert(dbSession, new GithubPermissionsMappingDto(uuidFactory.create(), mapping.githubRole(), mapping.sonarqubePermission())));
}

private static SonarqubePermissions getSonarqubePermissions(Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos) {
SonarqubePermissions.Builder builder = SonarqubePermissions.Builder.builder();
githubPermissionsMappingDtos.stream()
.map(GithubPermissionsMappingDto::sonarqubePermission)
.map(permissionAsStringToSonarqubePermission::get)
.forEach(builderConsumer -> builderConsumer.accept(builder));
return builder.build();
}

public GithubPermissionsMapping createPermissionMapping(GithubPermissionsMapping request) {
try (DbSession dbSession = dbClient.openSession(false)) {
validateCreatePermissionMappingRequest(request, dbSession);
toGithubPermissionsMappingDtos(request).forEach(dto -> githubPermissionsMappingDao.insert(dbSession, dto));
dbSession.commit();
return getPermissionsMappingForGithubRole(request.githubRole());
}
}

private void validateCreatePermissionMappingRequest(GithubPermissionsMapping request, DbSession dbSession) {
if (!getPermissionsMappingForGithubRole(dbSession, request.githubRole()).isEmpty()) {
throw new IllegalArgumentException(format("Role %s already exists, it can't be created again.", request.githubRole()));
}
if (conflictBaseRole(request.githubRole())) {
throw new IllegalArgumentException(format("Role %s can conflicts with a GitHub base role, please chose another name.", request.githubRole()));
}
if (noPermissionsGranted(request.permissions())) {
throw new IllegalArgumentException(format("Role %s has no permission set, please set at least one permission.", request.githubRole()));
}
}

private static boolean conflictBaseRole(String githubRole) {
return GITHUB_BASE_ROLES.stream()
.anyMatch(baseRole -> githubRole.toLowerCase(Locale.ROOT).equals(baseRole));
}

private static boolean noPermissionsGranted(SonarqubePermissions permissions) {
return !permissions.user() &&
!permissions.codeViewer() &&
!permissions.issueAdmin() &&
!permissions.securityHotspotAdmin() &&
!permissions.admin() &&
!permissions.scan();
}

private Set<GithubPermissionsMappingDto> toGithubPermissionsMappingDtos(GithubPermissionsMapping request) {
SonarqubePermissions permissions = request.permissions();
Set<GithubPermissionsMappingDto> githubPermissionsMappingDtos = new HashSet<>();

toGithubPermissionsMappingDto(permissions.user(), UserRole.USER, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);
toGithubPermissionsMappingDto(permissions.codeViewer(), UserRole.CODEVIEWER, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);
toGithubPermissionsMappingDto(permissions.issueAdmin(), UserRole.ISSUE_ADMIN, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);
toGithubPermissionsMappingDto(permissions.securityHotspotAdmin(), UserRole.SECURITYHOTSPOT_ADMIN, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);
toGithubPermissionsMappingDto(permissions.admin(), UserRole.ADMIN, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);
toGithubPermissionsMappingDto(permissions.scan(), UserRole.SCAN, request.githubRole()).ifPresent(githubPermissionsMappingDtos::add);

return githubPermissionsMappingDtos;
}

private Optional<GithubPermissionsMappingDto> toGithubPermissionsMappingDto(boolean granted, String permission, String githubRole) {
if (granted) {
return Optional.of(new GithubPermissionsMappingDto(uuidFactory.create(), githubRole, permission));
}
return Optional.empty();
}

}

+ 0
- 25
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/PermissionMappingChange.java Datei anzeigen

@@ -1,25 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.common.github.permissions;

import org.sonar.server.common.permission.Operation;

public record PermissionMappingChange(String githubRole, String sonarqubePermission, Operation operation) {
}

+ 0
- 80
server/sonar-webserver-common/src/main/java/org/sonar/server/common/github/permissions/SonarqubePermissions.java Datei anzeigen

@@ -1,80 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2023 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.common.github.permissions;

public record SonarqubePermissions(
boolean user,
boolean codeViewer,
boolean issueAdmin,
boolean securityHotspotAdmin,
boolean admin,
boolean scan) {


public static final class Builder {
private boolean user = false;
private boolean codeViewer = false;
private boolean issueAdmin = false;
private boolean securityHotspotAdmin = false;
private boolean admin = false;
private boolean scan = false;

private Builder() {
}

public static Builder builder() {
return new Builder();
}

public Builder user(boolean user) {
this.user = user;
return this;
}

public Builder codeViewer(boolean codeViewer) {
this.codeViewer = codeViewer;
return this;
}

public Builder issueAdmin(boolean issueAdmin) {
this.issueAdmin = issueAdmin;
return this;
}

public Builder securityHotspotAdmin(boolean securityHotspotAdmin) {
this.securityHotspotAdmin = securityHotspotAdmin;
return this;
}

public Builder admin(boolean admin) {
this.admin = admin;
return this;
}

public Builder scan(boolean scan) {
this.scan = scan;
return this;
}

public SonarqubePermissions build() {
return new SonarqubePermissions(user, codeViewer, issueAdmin, securityHotspotAdmin, admin, scan);
}
}
}

+ 0
- 2
server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java Datei anzeigen

@@ -75,7 +75,6 @@ import org.sonar.server.branch.ws.BranchWsModule;
import org.sonar.server.ce.CeModule;
import org.sonar.server.ce.projectdump.ProjectExportWsModule;
import org.sonar.server.ce.ws.CeWsModule;
import org.sonar.server.common.github.permissions.GithubPermissionsMappingService;
import org.sonar.server.component.ComponentCleanerService;
import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentService;
@@ -549,7 +548,6 @@ public class PlatformLevel4 extends PlatformLevel {
GithubApplicationHttpClientImpl.class,
GithubProvisioningConfigValidator.class,
GithubProvisioningWs.class,
GithubPermissionsMappingService.class,
BitbucketCloudRestClientConfiguration.class,
BitbucketServerRestClient.class,
GitlabHttpClient.class,

Laden…
Abbrechen
Speichern