diff options
Diffstat (limited to 'javatests/com/google/gerrit/acceptance/rest/project/GetBranchIT.java')
-rw-r--r-- | javatests/com/google/gerrit/acceptance/rest/project/GetBranchIT.java | 470 |
1 files changed, 470 insertions, 0 deletions
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/GetBranchIT.java b/javatests/com/google/gerrit/acceptance/rest/project/GetBranchIT.java new file mode 100644 index 0000000000..56265c6893 --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/rest/project/GetBranchIT.java @@ -0,0 +1,470 @@ +// Copyright (C) 2020 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.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS; +import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS; +import static com.google.gerrit.testing.GerritJUnit.assertThrows; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.acceptance.testsuite.group.GroupOperations; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations; +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.common.data.Permission; +import com.google.gerrit.extensions.api.changes.DraftInput; +import com.google.gerrit.extensions.api.projects.BranchInfo; +import com.google.gerrit.extensions.api.projects.TagInfo; +import com.google.gerrit.extensions.api.projects.TagInput; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.client.RefNames; +import com.google.gerrit.server.notedb.Sequences; +import com.google.gerrit.testing.ConfigSuite; +import com.google.inject.Inject; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.Repository; +import org.junit.Test; + +public class GetBranchIT extends AbstractDaemonTest { + @Inject private GroupOperations groupOperations; + @Inject private ProjectOperations projectOperations; + @Inject private RequestScopeOperations requestScopeOperations; + + @ConfigSuite.Config + public static Config skipFalse() { + Config config = new Config(); + config.setBoolean("auth", null, "skipFullRefEvaluationIfAllRefsAreVisible", false); + return config; + } + + @Test + public void cannotGetNonExistingBranch() { + assertBranchNotFound(project, RefNames.fullName("non-existing")); + } + + @Test + public void getBranch() throws Exception { + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(project, RefNames.fullName("master")); + } + + @Test + public void getBranchByShortName() throws Exception { + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(project, "master"); + } + + @Test + public void cannotGetNonVisibleBranch() throws Exception { + String branchName = "master"; + + // block read access to the branch + block(project, RefNames.fullName(branchName), Permission.READ, ANONYMOUS_USERS); + + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(project, RefNames.fullName(branchName)); + } + + @Test + public void cannotGetNonVisibleBranchByShortName() throws Exception { + String branchName = "master"; + + // block read access to the branch + block(project, RefNames.fullName(branchName), Permission.READ, ANONYMOUS_USERS); + + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(project, branchName); + } + + @Test + public void getChangeRef() throws Exception { + // create a change + Change.Id changeId = createChange("refs/for/master").getPatchSetId().changeId(); + + // a user without the 'Access Database' capability can see the change ref + requestScopeOperations.setApiUser(user.id()); + String changeRef = RefNames.patchSetRef(PatchSet.id(changeId, 1)); + assertBranchFound(project, changeRef); + } + + @Test + public void getChangeRefOfNonVisibleChange() throws Exception { + // create a change + String branchName = "master"; + Change.Id changeId = createChange("refs/for/" + branchName).getPatchSetId().changeId(); + + // block read access to the branch + block(project, RefNames.fullName(branchName), Permission.READ, ANONYMOUS_USERS); + + // a user without the 'Access Database' capability cannot see the change ref + requestScopeOperations.setApiUser(user.id()); + String changeRef = RefNames.patchSetRef(PatchSet.id(changeId, 1)); + assertBranchNotFound(project, changeRef); + + // a user with the 'Access Database' capability can see the change ref + testGetRefWithAccessDatabase(project, changeRef); + } + + @Test + public void getChangeEditRef() throws Exception { + TestAccount user2 = accountCreator.user2(); + + // create a change + Change.Id changeId = createChange("refs/for/master").getPatchSetId().changeId(); + + // create a change edit by 'user' + requestScopeOperations.setApiUser(user.id()); + gApi.changes().id(changeId.get()).edit().create(); + + // every user can see their own change edit refs + String changeEditRef = RefNames.refsEdit(user.id(), changeId, PatchSet.id(changeId, 1)); + assertBranchFound(project, changeEditRef); + + // a user without the 'Access Database' capability cannot see the change edit ref of another + // user + requestScopeOperations.setApiUser(user2.id()); + assertBranchNotFound(project, changeEditRef); + + // a user with the 'Access Database' capability can see the change edit ref of another user + testGetRefWithAccessDatabase(project, changeEditRef); + } + + @Test + public void cannotGetChangeEditRefOfNonVisibleChange() throws Exception { + // create a change + String branchName = "master"; + Change.Id changeId = createChange("refs/for/" + branchName).getPatchSetId().changeId(); + + // create a change edit by 'user' + requestScopeOperations.setApiUser(user.id()); + gApi.changes().id(changeId.get()).edit().create(); + + // make the change non-visible by blocking read access on the destination + block(project, RefNames.fullName(branchName), Permission.READ, ANONYMOUS_USERS); + + // user cannot see their own change edit refs if the change is no longer visible + String changeEditRef = RefNames.refsEdit(user.id(), changeId, PatchSet.id(changeId, 1)); + assertBranchNotFound(project, changeEditRef); + + // a user with the 'Access Database' capability can see the change edit ref + testGetRefWithAccessDatabase(project, changeEditRef); + } + + @Test + public void getChangeMetaRef() throws Exception { + // create a change + Change.Id changeId = createChange("refs/for/master").getPatchSetId().changeId(); + + // A user without the 'Access Database' capability can see the change meta ref. + // This may be surprising, as 'Access Database' guards access to meta refs and the change meta + // ref is a meta ref, however change meta refs have been always visible to all users that can + // see the change and some tools rely on seeing these refs, so we have to keep the current + // behaviour. + requestScopeOperations.setApiUser(user.id()); + String changeMetaRef = RefNames.changeMetaRef(changeId); + assertBranchFound(project, changeMetaRef); + } + + @Test + public void getRefsMetaConfig() throws Exception { + // a non-project owner cannot get the refs/meta/config branch + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(project, RefNames.REFS_CONFIG); + + // a non-project owner cannot get the refs/meta/config branch even with the 'Access Database' + // capability + allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE); + try { + assertBranchNotFound(project, RefNames.REFS_CONFIG); + } finally { + removeGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE); + } + + requestScopeOperations.setApiUser(user.id()); + + // a project owner can get the refs/meta/config branch + allow(project, "refs/*", Permission.OWNER, REGISTERED_USERS); + assertBranchFound(project, RefNames.REFS_CONFIG); + } + + @Test + public void getUserRefOfOtherUser() throws Exception { + String userRef = RefNames.refsUsers(admin.id()); + + // a user without the 'Access Database' capability cannot see the user ref of another user + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(allUsers, userRef); + + // a user with the 'Access Database' capability can see the user ref of another user + testGetRefWithAccessDatabase(allUsers, userRef); + } + + @Test + public void getOwnUserRef() throws Exception { + // every user can see the own user ref + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(allUsers, RefNames.refsUsers(user.id())); + + // TODO: every user can see the own user ref via the magic ref/users/self ref + // requestScopeOperations.setApiUser(user.id()); + // assertBranchFound(allUsers, RefNames.REFS_USERS_SELF); + } + + @Test + public void getExternalIdsRefs() throws Exception { + // a user without the 'Access Database' capability cannot see the refs/meta/external-ids ref + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(allUsers, RefNames.REFS_EXTERNAL_IDS); + + // a user with the 'Access Database' capability can see the refs/meta/external-ids ref + testGetRefWithAccessDatabase(allUsers, RefNames.REFS_EXTERNAL_IDS); + } + + @Test + public void getGroupRef() throws Exception { + // create a group + AccountGroup.UUID ownerGroupUuid = + groupOperations.newGroup().name("owner-group").addMember(admin.id()).create(); + AccountGroup.UUID testGroupUuid = + groupOperations.newGroup().name("test-group").ownerGroupUuid(ownerGroupUuid).create(); + + // a non-group owner without the 'Access Database' capability cannot see the group ref + requestScopeOperations.setApiUser(user.id()); + String groupRef = RefNames.refsGroups(testGroupUuid); + assertBranchNotFound(allUsers, groupRef); + + // a non-group owner with the 'Access Database' capability can see the group ref + testGetRefWithAccessDatabase(allUsers, groupRef); + + // a group owner can see the group ref if the group ref is visible + groupOperations.group(ownerGroupUuid).forUpdate().addMember(user.id()).update(); + assertBranchFound(allUsers, groupRef); + + // A group owner cannot see the group ref if the group ref is not visible. + // The READ access for refs/groups/* must be blocked on All-Projects rather than All-Users. + // This is because READ access for refs/groups/* on All-Users is by default granted to + // REGISTERED_USERS, and if an ALLOW rule and a BLOCK rule are on the same project and ref, + // the ALLOW rule takes precedence. + block(allProjects, "refs/groups/*", Permission.READ, ANONYMOUS_USERS); + assertBranchNotFound(allUsers, groupRef); + } + + @Test + public void getGroupNamesRef() throws Exception { + // a user without the 'Access Database' capability cannot see the refs/meta/group-names ref + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(allUsers, RefNames.REFS_GROUPNAMES); + + // a user with the 'Access Database' capability can see the refs/meta/group-names ref + testGetRefWithAccessDatabase(allUsers, RefNames.REFS_GROUPNAMES); + } + + @Test + public void getDeletedGroupRef() throws Exception { + // Create a deleted group ref. We must create a directly in the repo, since group deletion is + // not supported yet. + String deletedGroupRef = RefNames.refsDeletedGroups(AccountGroup.uuid("deleted-group")); + try (TestRepository<Repository> testRepo = + new TestRepository<>(repoManager.openRepository(allUsers))) { + testRepo + .branch(deletedGroupRef) + .commit() + .message("Some Message") + .add("group.config", "content") + .create(); + } + + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(allUsers, deletedGroupRef); + + // a user with the 'Access Database' capability can see the deleted group ref + testGetRefWithAccessDatabase(allUsers, deletedGroupRef); + } + + @Test + public void getDraftCommentsRef() throws Exception { + TestAccount user2 = accountCreator.user2(); + + // create a change + String fileName = "a.txt"; + Change change = createChange("A Change", fileName, "content").getChange().change(); + + // create a draft comment by the by 'user' + requestScopeOperations.setApiUser(user.id()); + DraftInput draftInput = new DraftInput(); + draftInput.path = fileName; + draftInput.line = 0; + draftInput.message = "Some Comment"; + gApi.changes().id(change.getChangeId()).current().createDraft(draftInput); + + // every user can see their own draft comments refs + // TODO: is this a bug? + String draftCommentsRef = RefNames.refsDraftComments(change.getId(), user.id()); + assertBranchFound(allUsers, draftCommentsRef); + + // a user without the 'Access Database' capability cannot see the draft comments ref of another + // user + requestScopeOperations.setApiUser(user2.id()); + assertBranchNotFound(allUsers, draftCommentsRef); + + // a user with the 'Access Database' capability can see the draft comments ref of another user + testGetRefWithAccessDatabase(allUsers, draftCommentsRef); + } + + @Test + public void getStarredChangesRef() throws Exception { + TestAccount user2 = accountCreator.user2(); + + // create a change + Change change = createChange().getChange().change(); + + // let user star the change + requestScopeOperations.setApiUser(user.id()); + gApi.accounts().self().starChange(Integer.toString(change.getChangeId())); + + // every user can see their own starred changes refs + // TODO: is this a bug? + String starredChangesRef = RefNames.refsStarredChanges(change.getId(), user.id()); + assertBranchFound(allUsers, starredChangesRef); + + // a user without the 'Access Database' capability cannot see the starred changes ref of another + // user + requestScopeOperations.setApiUser(user2.id()); + assertBranchNotFound(allUsers, starredChangesRef); + + // a user with the 'Access Database' capability can see the starred changes ref of another user + testGetRefWithAccessDatabase(allUsers, starredChangesRef); + } + + @Test + public void getTagRef() throws Exception { + // create a tag + TagInput input = new TagInput(); + input.message = "My Tag"; + input.revision = projectOperations.project(project).getHead("master").name(); + TagInfo tagInfo = gApi.projects().name(project.get()).tag("my-tag").create(input).get(); + + // any user who can see the project, can see the tag + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(project, tagInfo.ref); + } + + @Test + public void cannotGetTagRefThatPointsToNonVisibleBranch() throws Exception { + // create a tag + TagInput input = new TagInput(); + input.message = "My Tag"; + input.revision = projectOperations.project(project).getHead("master").name(); + TagInfo tagInfo = gApi.projects().name(project.get()).tag("my-tag").create(input).get(); + + // block read access to the branch + block(allProjects, RefNames.fullName("master"), Permission.READ, ANONYMOUS_USERS); + + // if the user cannot see the project, the tag is not visible + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(project, tagInfo.ref); + } + + @Test + public void getSymbolicRef() throws Exception { + // 'HEAD' is visible since it points to 'master' that is visible + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(project, "HEAD"); + } + + @Test + public void cannotGetSymbolicRefThatPointsToNonVisibleBranch() throws Exception { + // block read access to the branch to which HEAD points by default + block(allProjects, RefNames.fullName("master"), Permission.READ, ANONYMOUS_USERS); + + // since 'master' is not visible, 'HEAD' which points to 'master' is also not visible + requestScopeOperations.setApiUser(user.id()); + assertBranchNotFound(project, "HEAD"); + } + + @Test + public void getAccountSequenceRef() throws Exception { + // a user without the 'Access Database' capability cannot see the refs/sequences/accounts ref + requestScopeOperations.setApiUser(user.id()); + String accountSequenceRef = RefNames.REFS_SEQUENCES + Sequences.NAME_ACCOUNTS; + assertBranchNotFound(allUsers, accountSequenceRef); + + // a user with the 'Access Database' capability can see the refs/sequences/accounts ref + testGetRefWithAccessDatabase(allUsers, accountSequenceRef); + } + + @Test + public void getChangeSequenceRef() throws Exception { + // a user without the 'Access Database' capability cannot see the refs/sequences/changes ref + requestScopeOperations.setApiUser(user.id()); + String changeSequenceRef = RefNames.REFS_SEQUENCES + Sequences.NAME_CHANGES; + assertBranchNotFound(allProjects, changeSequenceRef); + + // a user with the 'Access Database' capability can see the refs/sequences/changes ref + testGetRefWithAccessDatabase(allProjects, changeSequenceRef); + } + + @Test + public void getGroupSequenceRef() throws Exception { + // a user without the 'Access Database' capability cannot see the refs/sequences/groups ref + requestScopeOperations.setApiUser(user.id()); + String groupSequenceRef = RefNames.REFS_SEQUENCES + Sequences.NAME_GROUPS; + assertBranchNotFound(allUsers, groupSequenceRef); + + // a user with the 'Access Database' capability can see the refs/sequences/groups ref + testGetRefWithAccessDatabase(allUsers, groupSequenceRef); + } + + @Test + public void getVersionMetaRef() throws Exception { + // TODO: a user without the 'Access Database' capability cannot see the refs/meta/version ref + // requestScopeOperations.setApiUser(user.id()); + // assertBranchNotFound(allProjects, RefNames.REFS_VERSION); + + // a user with the 'Access Database' capability can see the refs/meta/vaersion ref + testGetRefWithAccessDatabase(allProjects, RefNames.REFS_VERSION); + } + + private void testGetRefWithAccessDatabase(Project.NameKey project, String ref) throws Exception { + allowGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE); + try { + requestScopeOperations.setApiUser(user.id()); + assertBranchFound(project, ref); + } finally { + removeGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE); + } + } + + private void assertBranchNotFound(Project.NameKey project, String ref) { + ResourceNotFoundException exception = + assertThrows( + ResourceNotFoundException.class, + () -> gApi.projects().name(project.get()).branch(ref).get()); + assertThat(exception).hasMessageThat().isEqualTo("Not found: " + ref); + } + + private void assertBranchFound(Project.NameKey project, String ref) throws RestApiException { + BranchInfo branchInfo = gApi.projects().name(project.get()).branch(ref).get(); + assertThat(branchInfo.ref).isEqualTo(RefNames.fullName(ref)); + } +} |