| // Copyright (C) 2016 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package com.google.gerrit.acceptance.rest.project; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.common.truth.Truth8.assertThat; |
| import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES; |
| import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; |
| |
| import com.google.gerrit.acceptance.AbstractDaemonTest; |
| import com.google.gerrit.acceptance.GitUtil; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.common.data.AccessSection; |
| import com.google.gerrit.common.data.GlobalCapability; |
| import com.google.gerrit.common.data.Permission; |
| import com.google.gerrit.extensions.api.access.AccessSectionInfo; |
| import com.google.gerrit.extensions.api.access.PermissionInfo; |
| import com.google.gerrit.extensions.api.access.PermissionRuleInfo; |
| import com.google.gerrit.extensions.api.access.ProjectAccessInfo; |
| import com.google.gerrit.extensions.api.access.ProjectAccessInput; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.api.projects.BranchInfo; |
| import com.google.gerrit.extensions.api.projects.ProjectApi; |
| import com.google.gerrit.extensions.client.ChangeStatus; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.extensions.common.GroupInfo; |
| import com.google.gerrit.extensions.common.WebLinkInfo; |
| import com.google.gerrit.extensions.registration.DynamicSet; |
| import com.google.gerrit.extensions.registration.RegistrationHandle; |
| import com.google.gerrit.extensions.restapi.AuthException; |
| import com.google.gerrit.extensions.restapi.BadRequestException; |
| import com.google.gerrit.extensions.restapi.ResourceNotFoundException; |
| import com.google.gerrit.extensions.webui.FileHistoryWebLink; |
| import com.google.gerrit.reviewdb.client.Project; |
| import com.google.gerrit.reviewdb.client.RefNames; |
| import com.google.gerrit.server.config.AllProjectsNameProvider; |
| import com.google.gerrit.server.group.SystemGroupBackend; |
| import com.google.gerrit.server.project.ProjectConfig; |
| import com.google.inject.Inject; |
| import java.util.HashMap; |
| import java.util.Map; |
| import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository; |
| import org.eclipse.jgit.junit.TestRepository; |
| import org.eclipse.jgit.lib.Config; |
| import org.eclipse.jgit.lib.Constants; |
| import org.eclipse.jgit.lib.RefUpdate; |
| import org.eclipse.jgit.lib.RefUpdate.Result; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class AccessIT extends AbstractDaemonTest { |
| |
| private static final String PROJECT_NAME = "newProject"; |
| |
| private static final String REFS_ALL = Constants.R_REFS + "*"; |
| private static final String REFS_HEADS = Constants.R_HEADS + "*"; |
| |
| private static final String LABEL_CODE_REVIEW = "Code-Review"; |
| |
| private Project.NameKey newProjectName; |
| |
| @Inject private DynamicSet<FileHistoryWebLink> fileHistoryWebLinkDynamicSet; |
| |
| @Before |
| public void setUp() throws Exception { |
| newProjectName = createProject(PROJECT_NAME); |
| } |
| |
| @Test |
| public void getDefaultInheritance() throws Exception { |
| String inheritedName = pApi().access().inheritsFrom.name; |
| assertThat(inheritedName).isEqualTo(AllProjectsNameProvider.DEFAULT); |
| } |
| |
| @Test |
| public void webLink() throws Exception { |
| RegistrationHandle handle = |
| fileHistoryWebLinkDynamicSet.add( |
| "gerrit", |
| new FileHistoryWebLink() { |
| @Override |
| public WebLinkInfo getFileHistoryWebLink( |
| String projectName, String revision, String fileName) { |
| return new WebLinkInfo( |
| "name", "imageURL", "http://view/" + projectName + "/" + fileName); |
| } |
| }); |
| try { |
| ProjectAccessInfo info = pApi().access(); |
| assertThat(info.configWebLinks).hasSize(1); |
| assertThat(info.configWebLinks.get(0).url) |
| .isEqualTo("http://view/" + newProjectName + "/project.config"); |
| } finally { |
| handle.remove(); |
| } |
| } |
| |
| @Test |
| public void webLinkNoRefsMetaConfig() throws Exception { |
| RegistrationHandle handle = |
| fileHistoryWebLinkDynamicSet.add( |
| "gerrit", |
| new FileHistoryWebLink() { |
| @Override |
| public WebLinkInfo getFileHistoryWebLink( |
| String projectName, String revision, String fileName) { |
| return new WebLinkInfo( |
| "name", "imageURL", "http://view/" + projectName + "/" + fileName); |
| } |
| }); |
| try (Repository repo = repoManager.openRepository(newProjectName)) { |
| RefUpdate u = repo.updateRef(RefNames.REFS_CONFIG); |
| u.setForceUpdate(true); |
| assertThat(u.delete()).isEqualTo(Result.FORCED); |
| |
| // This should not crash. |
| pApi().access(); |
| } finally { |
| handle.remove(); |
| } |
| } |
| |
| @Test |
| public void addAccessSection() throws Exception { |
| RevCommit initialHead = getRemoteHead(newProjectName, RefNames.REFS_CONFIG); |
| |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| accessInput.add.put(REFS_HEADS, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| assertThat(pApi().access().local).isEqualTo(accessInput.add); |
| |
| RevCommit updatedHead = getRemoteHead(newProjectName, RefNames.REFS_CONFIG); |
| eventRecorder.assertRefUpdatedEvents( |
| newProjectName.get(), RefNames.REFS_CONFIG, null, initialHead, initialHead, updatedHead); |
| } |
| |
| @Test |
| public void createAccessChangeNop() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| exception.expect(BadRequestException.class); |
| pApi().accessChange(accessInput); |
| } |
| |
| @Test |
| public void createAccessChangeEmptyConfig() throws Exception { |
| try (Repository repo = repoManager.openRepository(newProjectName)) { |
| RefUpdate ru = repo.updateRef(RefNames.REFS_CONFIG); |
| ru.setForceUpdate(true); |
| assertThat(ru.delete()).isEqualTo(Result.FORCED); |
| |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| PermissionInfo read = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.BLOCK, false); |
| read.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| accessSection.permissions.put(Permission.READ, read); |
| accessInput.add.put(REFS_HEADS, accessSection); |
| |
| ChangeInfo out = pApi().accessChange(accessInput); |
| assertThat(out.status).isEqualTo(ChangeStatus.NEW); |
| } |
| } |
| |
| @Test |
| public void createAccessChange() throws Exception { |
| allow(newProjectName, RefNames.REFS_CONFIG, Permission.READ, REGISTERED_USERS); |
| // User can see the branch |
| setApiUser(user); |
| pApi().branch("refs/heads/master").get(); |
| |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| |
| // Deny read to registered users. |
| PermissionInfo read = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| read.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| read.exclusive = true; |
| accessSection.permissions.put(Permission.READ, read); |
| accessInput.add.put(REFS_HEADS, accessSection); |
| |
| setApiUser(user); |
| ChangeInfo out = pApi().accessChange(accessInput); |
| |
| assertThat(out.project).isEqualTo(newProjectName.get()); |
| assertThat(out.branch).isEqualTo(RefNames.REFS_CONFIG); |
| assertThat(out.status).isEqualTo(ChangeStatus.NEW); |
| assertThat(out.submitted).isNull(); |
| |
| setApiUser(admin); |
| |
| ChangeInfo c = gApi.changes().id(out._number).get(MESSAGES); |
| assertThat(c.messages.stream().map(m -> m.message)).containsExactly("Uploaded patch set 1"); |
| |
| ReviewInput reviewIn = new ReviewInput(); |
| reviewIn.label("Code-Review", (short) 2); |
| gApi.changes().id(out._number).current().review(reviewIn); |
| gApi.changes().id(out._number).current().submit(); |
| |
| // check that the change took effect. |
| setApiUser(user); |
| try { |
| BranchInfo info = pApi().branch("refs/heads/master").get(); |
| fail("wanted failure, got " + newGson().toJson(info)); |
| } catch (ResourceNotFoundException e) { |
| // OK. |
| } |
| |
| // Restore. |
| accessInput.add.clear(); |
| accessInput.remove.put(REFS_HEADS, accessSection); |
| setApiUser(user); |
| |
| setApiUser(admin); |
| out = pApi().accessChange(accessInput); |
| |
| gApi.changes().id(out._number).current().review(reviewIn); |
| gApi.changes().id(out._number).current().submit(); |
| |
| // Now it works again. |
| setApiUser(user); |
| pApi().branch("refs/heads/master").get(); |
| } |
| |
| @Test |
| public void removePermission() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| accessInput.add.put(REFS_HEADS, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| // Remove specific permission |
| AccessSectionInfo accessSectionToRemove = newAccessSectionInfo(); |
| accessSectionToRemove.permissions.put( |
| Permission.LABEL + LABEL_CODE_REVIEW, newPermissionInfo()); |
| ProjectAccessInput removal = newProjectAccessInput(); |
| removal.remove.put(REFS_HEADS, accessSectionToRemove); |
| pApi().access(removal); |
| |
| // Remove locally |
| accessInput.add.get(REFS_HEADS).permissions.remove(Permission.LABEL + LABEL_CODE_REVIEW); |
| |
| // Check |
| assertThat(pApi().access().local).isEqualTo(accessInput.add); |
| } |
| |
| @Test |
| public void removePermissionRule() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| accessInput.add.put(REFS_HEADS, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| // Remove specific permission rule |
| AccessSectionInfo accessSectionToRemove = newAccessSectionInfo(); |
| PermissionInfo codeReview = newPermissionInfo(); |
| codeReview.label = LABEL_CODE_REVIEW; |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| codeReview.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| accessSectionToRemove.permissions.put(Permission.LABEL + LABEL_CODE_REVIEW, codeReview); |
| ProjectAccessInput removal = newProjectAccessInput(); |
| removal.remove.put(REFS_HEADS, accessSectionToRemove); |
| pApi().access(removal); |
| |
| // Remove locally |
| accessInput |
| .add |
| .get(REFS_HEADS) |
| .permissions |
| .get(Permission.LABEL + LABEL_CODE_REVIEW) |
| .rules |
| .remove(SystemGroupBackend.REGISTERED_USERS.get()); |
| |
| // Check |
| assertThat(pApi().access().local).isEqualTo(accessInput.add); |
| } |
| |
| @Test |
| public void removePermissionRulesAndCleanupEmptyEntries() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| accessInput.add.put(REFS_HEADS, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| // Remove specific permission rules |
| AccessSectionInfo accessSectionToRemove = newAccessSectionInfo(); |
| PermissionInfo codeReview = newPermissionInfo(); |
| codeReview.label = LABEL_CODE_REVIEW; |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| codeReview.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| codeReview.rules.put(SystemGroupBackend.PROJECT_OWNERS.get(), pri); |
| accessSectionToRemove.permissions.put(Permission.LABEL + LABEL_CODE_REVIEW, codeReview); |
| ProjectAccessInput removal = newProjectAccessInput(); |
| removal.remove.put(REFS_HEADS, accessSectionToRemove); |
| pApi().access(removal); |
| |
| // Remove locally |
| accessInput.add.get(REFS_HEADS).permissions.remove(Permission.LABEL + LABEL_CODE_REVIEW); |
| |
| // Check |
| assertThat(pApi().access().local).isEqualTo(accessInput.add); |
| } |
| |
| @Test |
| public void getPermissionsWithDisallowedUser() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createAccessSectionInfoDenyAll(); |
| |
| // Disallow READ |
| accessInput.add.put(REFS_ALL, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| setApiUser(user); |
| exception.expect(ResourceNotFoundException.class); |
| pApi().access(); |
| } |
| |
| @Test |
| public void setPermissionsWithDisallowedUser() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createAccessSectionInfoDenyAll(); |
| |
| // Disallow READ |
| accessInput.add.put(REFS_ALL, accessSectionInfo); |
| pApi().access(accessInput); |
| |
| // Create a change to apply |
| ProjectAccessInput accessInfoToApply = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfoToApply = createDefaultAccessSectionInfo(); |
| accessInfoToApply.add.put(REFS_HEADS, accessSectionInfoToApply); |
| |
| setApiUser(user); |
| exception.expect(ResourceNotFoundException.class); |
| pApi().access(); |
| } |
| |
| @Test |
| public void permissionsGroupMap() throws Exception { |
| // Add initial permission set |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| |
| PermissionInfo push = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| push.rules.put(SystemGroupBackend.PROJECT_OWNERS.get(), pri); |
| accessSection.permissions.put(Permission.PUSH, push); |
| |
| PermissionInfo read = newPermissionInfo(); |
| pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| read.rules.put(SystemGroupBackend.ANONYMOUS_USERS.get(), pri); |
| accessSection.permissions.put(Permission.READ, read); |
| |
| accessInput.add.put(REFS_ALL, accessSection); |
| ProjectAccessInfo result = pApi().access(accessInput); |
| assertThat(result.groups.keySet()) |
| .containsExactly( |
| SystemGroupBackend.PROJECT_OWNERS.get(), SystemGroupBackend.ANONYMOUS_USERS.get()); |
| |
| // Check the name, which is what the UI cares about; exhaustive |
| // coverage of GroupInfo should be in groups REST API tests. |
| assertThat(result.groups.get(SystemGroupBackend.PROJECT_OWNERS.get()).name) |
| .isEqualTo("Project Owners"); |
| // Strip the ID, since it is in the key. |
| assertThat(result.groups.get(SystemGroupBackend.PROJECT_OWNERS.get()).id).isNull(); |
| |
| // Get call returns groups too. |
| ProjectAccessInfo loggedInResult = pApi().access(); |
| assertThat(loggedInResult.groups.keySet()) |
| .containsExactly( |
| SystemGroupBackend.PROJECT_OWNERS.get(), SystemGroupBackend.ANONYMOUS_USERS.get()); |
| |
| GroupInfo owners = loggedInResult.groups.get(SystemGroupBackend.PROJECT_OWNERS.get()); |
| assertThat(owners.name).isEqualTo("Project Owners"); |
| assertThat(owners.id).isNull(); |
| assertThat(owners.members).isNull(); |
| assertThat(owners.includes).isNull(); |
| |
| // PROJECT_OWNERS is invisible to anonymous user, but GetAccess disregards visibility. |
| setApiUserAnonymous(); |
| ProjectAccessInfo anonResult = pApi().access(); |
| assertThat(anonResult.groups.keySet()) |
| .containsExactly( |
| SystemGroupBackend.PROJECT_OWNERS.get(), SystemGroupBackend.ANONYMOUS_USERS.get()); |
| } |
| |
| @Test |
| public void updateParentAsUser() throws Exception { |
| // Create child |
| String newParentProjectName = createProject(PROJECT_NAME + "PA").get(); |
| |
| // Set new parent |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| accessInput.parent = newParentProjectName; |
| |
| setApiUser(user); |
| exception.expect(AuthException.class); |
| exception.expectMessage("administrate server not permitted"); |
| pApi().access(accessInput); |
| } |
| |
| @Test |
| public void updateParentAsAdministrator() throws Exception { |
| // Create parent |
| String newParentProjectName = createProject(PROJECT_NAME + "PA").get(); |
| |
| // Set new parent |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| accessInput.parent = newParentProjectName; |
| |
| pApi().access(accessInput); |
| |
| assertThat(pApi().access().inheritsFrom.name).isEqualTo(newParentProjectName); |
| } |
| |
| @Test |
| public void addGlobalCapabilityAsUser() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultGlobalCapabilitiesAccessSectionInfo(); |
| |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| setApiUser(user); |
| exception.expect(AuthException.class); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| } |
| |
| @Test |
| public void addGlobalCapabilityAsAdmin() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultGlobalCapabilitiesAccessSectionInfo(); |
| |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| ProjectAccessInfo updatedAccessSectionInfo = |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| assertThat( |
| updatedAccessSectionInfo |
| .local |
| .get(AccessSection.GLOBAL_CAPABILITIES) |
| .permissions |
| .keySet()) |
| .containsAllIn(accessSectionInfo.permissions.keySet()); |
| } |
| |
| @Test |
| public void addGlobalCapabilityForNonRootProject() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultGlobalCapabilitiesAccessSectionInfo(); |
| |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| exception.expect(BadRequestException.class); |
| pApi().access(accessInput); |
| } |
| |
| @Test |
| public void addNonGlobalCapabilityToGlobalCapabilities() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = newAccessSectionInfo(); |
| |
| PermissionInfo permissionInfo = newPermissionInfo(); |
| permissionInfo.rules.put(adminGroupUuid().get(), null); |
| accessSectionInfo.permissions.put(Permission.PUSH, permissionInfo); |
| |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| exception.expect(BadRequestException.class); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| } |
| |
| @Test |
| public void removeGlobalCapabilityAsUser() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultGlobalCapabilitiesAccessSectionInfo(); |
| |
| accessInput.remove.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| setApiUser(user); |
| exception.expect(AuthException.class); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| } |
| |
| @Test |
| public void removeGlobalCapabilityAsAdmin() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = newAccessSectionInfo(); |
| |
| PermissionInfo permissionInfo = newPermissionInfo(); |
| permissionInfo.rules.put(adminGroupUuid().get(), null); |
| accessSectionInfo.permissions.put(GlobalCapability.ACCESS_DATABASE, permissionInfo); |
| |
| // Add and validate first as removing existing privileges such as |
| // administrateServer would break upcoming tests |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| ProjectAccessInfo updatedProjectAccessInfo = |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| assertThat( |
| updatedProjectAccessInfo |
| .local |
| .get(AccessSection.GLOBAL_CAPABILITIES) |
| .permissions |
| .keySet()) |
| .containsAllIn(accessSectionInfo.permissions.keySet()); |
| |
| // Remove |
| accessInput.add.clear(); |
| accessInput.remove.put(AccessSection.GLOBAL_CAPABILITIES, accessSectionInfo); |
| |
| updatedProjectAccessInfo = gApi.projects().name(allProjects.get()).access(accessInput); |
| assertThat( |
| updatedProjectAccessInfo |
| .local |
| .get(AccessSection.GLOBAL_CAPABILITIES) |
| .permissions |
| .keySet()) |
| .containsNoneIn(accessSectionInfo.permissions.keySet()); |
| } |
| |
| @Test |
| public void unknownPermissionRemainsUnchanged() throws Exception { |
| String access = "access"; |
| String unknownPermission = "unknownPermission"; |
| String registeredUsers = "group Registered Users"; |
| String refsFor = "refs/for/*"; |
| // Clone repository to forcefully add permission |
| TestRepository<InMemoryRepository> allProjectsRepo = cloneProject(allProjects, admin); |
| |
| // Fetch permission ref |
| GitUtil.fetch(allProjectsRepo, "refs/meta/config:cfg"); |
| allProjectsRepo.reset("cfg"); |
| |
| // Load current permissions |
| String config = |
| gApi.projects() |
| .name(allProjects.get()) |
| .branch(RefNames.REFS_CONFIG) |
| .file(ProjectConfig.PROJECT_CONFIG) |
| .asString(); |
| |
| // Append and push unknown permission |
| Config cfg = new Config(); |
| cfg.fromText(config); |
| cfg.setString(access, refsFor, unknownPermission, registeredUsers); |
| config = cfg.toText(); |
| PushOneCommit push = |
| pushFactory.create( |
| db, admin.getIdent(), allProjectsRepo, "Subject", ProjectConfig.PROJECT_CONFIG, config); |
| push.to(RefNames.REFS_CONFIG).assertOkStatus(); |
| |
| // Verify that unknownPermission is present |
| config = |
| gApi.projects() |
| .name(allProjects.get()) |
| .branch(RefNames.REFS_CONFIG) |
| .file(ProjectConfig.PROJECT_CONFIG) |
| .asString(); |
| cfg.fromText(config); |
| assertThat(cfg.getString(access, refsFor, unknownPermission)).isEqualTo(registeredUsers); |
| |
| // Make permission change through API |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| accessInput.add.put(refsFor, accessSectionInfo); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| accessInput.add.clear(); |
| accessInput.remove.put(refsFor, accessSectionInfo); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| |
| // Verify that unknownPermission is still present |
| config = |
| gApi.projects() |
| .name(allProjects.get()) |
| .branch(RefNames.REFS_CONFIG) |
| .file(ProjectConfig.PROJECT_CONFIG) |
| .asString(); |
| cfg.fromText(config); |
| assertThat(cfg.getString(access, refsFor, unknownPermission)).isEqualTo(registeredUsers); |
| } |
| |
| @Test |
| public void allUsersCanOnlyInheritFromAllProjects() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| accessInput.parent = project.get(); |
| exception.expect(BadRequestException.class); |
| exception.expectMessage(allUsers.get() + " must inherit from " + allProjects.get()); |
| gApi.projects().name(allUsers.get()).access(accessInput); |
| } |
| |
| @Test |
| public void syncCreateGroupPermission() throws Exception { |
| // Grant CREATE_GROUP to Registered Users |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| PermissionInfo createGroup = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| createGroup.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| accessSection.permissions.put(GlobalCapability.CREATE_GROUP, createGroup); |
| accessInput.add.put(AccessSection.GLOBAL_CAPABILITIES, accessSection); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| |
| // Assert that the permission was synced from All-Projects (global) to All-Users (ref) |
| Map<String, AccessSectionInfo> local = gApi.projects().name("All-Users").access().local; |
| assertThat(local).isNotNull(); |
| assertThat(local).containsKey(RefNames.REFS_GROUPS + "*"); |
| Map<String, PermissionInfo> permissions = local.get(RefNames.REFS_GROUPS + "*").permissions; |
| assertThat(permissions).hasSize(2); |
| // READ is the default permission and should be preserved by the syncer |
| assertThat(permissions.keySet()).containsExactly(Permission.READ, Permission.CREATE); |
| Map<String, PermissionRuleInfo> rules = permissions.get(Permission.CREATE).rules; |
| assertThat(rules.values()).containsExactly(pri); |
| |
| // Revoke the permission |
| accessInput.add.clear(); |
| accessInput.remove.put(AccessSection.GLOBAL_CAPABILITIES, accessSection); |
| gApi.projects().name(allProjects.get()).access(accessInput); |
| |
| // Assert that the permission was synced from All-Projects (global) to All-Users (ref) |
| Map<String, AccessSectionInfo> local2 = gApi.projects().name("All-Users").access().local; |
| assertThat(local2).isNotNull(); |
| assertThat(local2).containsKey(RefNames.REFS_GROUPS + "*"); |
| Map<String, PermissionInfo> permissions2 = local2.get(RefNames.REFS_GROUPS + "*").permissions; |
| assertThat(permissions2).hasSize(1); |
| // READ is the default permission and should be preserved by the syncer |
| assertThat(permissions2.keySet()).containsExactly(Permission.READ); |
| } |
| |
| @Test |
| public void addAccessSectionForInvalidRef() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| // 'refs/heads/stable_*' is invalid, correct would be '^refs/heads/stable_.*' |
| String invalidRef = Constants.R_HEADS + "stable_*"; |
| accessInput.add.put(invalidRef, accessSectionInfo); |
| |
| exception.expect(BadRequestException.class); |
| exception.expectMessage("Invalid Name: " + invalidRef); |
| pApi().access(accessInput); |
| } |
| |
| @Test |
| public void createAccessChangeWithAccessSectionForInvalidRef() throws Exception { |
| ProjectAccessInput accessInput = newProjectAccessInput(); |
| AccessSectionInfo accessSectionInfo = createDefaultAccessSectionInfo(); |
| |
| // 'refs/heads/stable_*' is invalid, correct would be '^refs/heads/stable_.*' |
| String invalidRef = Constants.R_HEADS + "stable_*"; |
| accessInput.add.put(invalidRef, accessSectionInfo); |
| |
| exception.expect(BadRequestException.class); |
| exception.expectMessage("Invalid Name: " + invalidRef); |
| pApi().accessChange(accessInput); |
| } |
| |
| private ProjectApi pApi() throws Exception { |
| return gApi.projects().name(newProjectName.get()); |
| } |
| |
| private ProjectAccessInput newProjectAccessInput() { |
| ProjectAccessInput p = new ProjectAccessInput(); |
| p.add = new HashMap<>(); |
| p.remove = new HashMap<>(); |
| return p; |
| } |
| |
| private PermissionInfo newPermissionInfo() { |
| PermissionInfo p = new PermissionInfo(null, null); |
| p.rules = new HashMap<>(); |
| return p; |
| } |
| |
| private AccessSectionInfo newAccessSectionInfo() { |
| AccessSectionInfo a = new AccessSectionInfo(); |
| a.permissions = new HashMap<>(); |
| return a; |
| } |
| |
| private AccessSectionInfo createDefaultAccessSectionInfo() { |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| |
| PermissionInfo push = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| push.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| accessSection.permissions.put(Permission.PUSH, push); |
| |
| PermissionInfo codeReview = newPermissionInfo(); |
| codeReview.label = LABEL_CODE_REVIEW; |
| pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| codeReview.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| |
| pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| pri.max = 1; |
| pri.min = -1; |
| codeReview.rules.put(SystemGroupBackend.PROJECT_OWNERS.get(), pri); |
| accessSection.permissions.put(Permission.LABEL + LABEL_CODE_REVIEW, codeReview); |
| |
| return accessSection; |
| } |
| |
| private AccessSectionInfo createDefaultGlobalCapabilitiesAccessSectionInfo() { |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| |
| PermissionInfo email = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.ALLOW, false); |
| email.rules.put(SystemGroupBackend.REGISTERED_USERS.get(), pri); |
| accessSection.permissions.put(GlobalCapability.EMAIL_REVIEWERS, email); |
| |
| return accessSection; |
| } |
| |
| private AccessSectionInfo createAccessSectionInfoDenyAll() { |
| AccessSectionInfo accessSection = newAccessSectionInfo(); |
| |
| PermissionInfo read = newPermissionInfo(); |
| PermissionRuleInfo pri = new PermissionRuleInfo(PermissionRuleInfo.Action.DENY, false); |
| read.rules.put(SystemGroupBackend.ANONYMOUS_USERS.get(), pri); |
| accessSection.permissions.put(Permission.READ, read); |
| |
| return accessSection; |
| } |
| } |