Merge changes I7e6fbabb,Iddf6f9b3,Iaa258788,I38ae31cd
* changes:
CheckAccess: print a useful message if no rules apply
Clarify some methods in the permission APIs
restapi/project: move CheckAccessReadView into CheckAccess
restapi/project: add some comments
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index 50ebad7..a809eab 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -1848,8 +1848,9 @@
Gets whether the source is mergeable with the target branch.
-The `source` query parameter is required, which can be anything that could be
-resolved to a commit, see examples of the `source` attribute in
+The `source` query parameter is required, which can be anything that
+could be resolved to a commit, and is visible to the caller. See
+examples of the `source` attribute in
link:rest-api-changes.html#merge-input[MergeInput].
Also takes an optional parameter `strategy`, which can be `recursive`, `resolve`,
diff --git a/java/com/google/gerrit/entities/Permission.java b/java/com/google/gerrit/entities/Permission.java
index 3f04fa5..322c79e 100644
--- a/java/com/google/gerrit/entities/Permission.java
+++ b/java/com/google/gerrit/entities/Permission.java
@@ -140,6 +140,7 @@
return true;
}
+ /** The permission name, eg. {@code Permission.SUBMIT} */
public abstract String getName();
protected abstract boolean isExclusiveGroup();
diff --git a/java/com/google/gerrit/server/permissions/GlobalPermission.java b/java/com/google/gerrit/server/permissions/GlobalPermission.java
index 07c9e84..d4f22e6 100644
--- a/java/com/google/gerrit/server/permissions/GlobalPermission.java
+++ b/java/com/google/gerrit/server/permissions/GlobalPermission.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
+import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.CapabilityScope;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
@@ -31,7 +32,12 @@
import java.util.Optional;
import java.util.Set;
-/** Global server permissions built into Gerrit. */
+/**
+ * Global server permissions built into Gerrit.
+ *
+ * <p>See also {@link GlobalCapability} which lists the equivalent strings used in the
+ * refs/meta/config settings in All-Projects.
+ */
public enum GlobalPermission implements GlobalOrPluginPermission {
ACCESS_DATABASE,
ADMINISTRATE_SERVER,
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index 89038e2..a1c48bc 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -385,6 +385,7 @@
this.accountsSection = accountsSection;
}
+ /** Returns an access section, {@code name} typically is a ref pattern. */
public AccessSection getAccessSection(String name) {
return accessSections.get(name);
}
diff --git a/java/com/google/gerrit/server/restapi/project/CheckAccess.java b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
index 4ef724a..37616cd 100644
--- a/java/com/google/gerrit/server/restapi/project/CheckAccess.java
+++ b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2018 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.
@@ -17,6 +17,7 @@
import static com.google.gerrit.entities.RefNames.REFS_HEADS;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.extensions.api.config.AccessCheckInfo;
@@ -25,7 +26,7 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
+import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.account.AccountResolver;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.logging.TraceContext;
@@ -37,15 +38,14 @@
import com.google.gerrit.server.permissions.RefPermission;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
-import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Optional;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Repository;
+import org.kohsuke.args4j.Option;
-@Singleton
-public class CheckAccess implements RestModifyView<ProjectResource, AccessCheckInput> {
+public class CheckAccess implements RestReadView<ProjectResource> {
private final AccountResolver accountResolver;
private final PermissionBackend permissionBackend;
private final GitRepositoryManager gitRepositoryManager;
@@ -60,7 +60,15 @@
this.gitRepositoryManager = gitRepositoryManager;
}
- @Override
+ @Option(name = "--ref", usage = "ref name to check permission for")
+ String refName;
+
+ @Option(name = "--account", usage = "account to check acccess for")
+ String account;
+
+ @Option(name = "--perm", usage = "permission to check; default: read of any ref.")
+ String permission;
+
public Response<AccessCheckInfo> apply(ProjectResource rsrc, AccessCheckInput input)
throws PermissionBackendException, RestApiException, IOException, ConfigInvalidException {
permissionBackend.user(rsrc.getUser()).check(GlobalPermission.VIEW_ACCESS);
@@ -142,6 +150,22 @@
info.status = statusCode;
info.message = message;
info.debugLogs = traceContext.getAclLogRecords();
+ if (info.debugLogs.isEmpty()) {
+ info.debugLogs =
+ ImmutableList.of("Found no rules that apply, so defaulting to no permission");
+ }
return info;
}
+
+ @Override
+ public Response<AccessCheckInfo> apply(ProjectResource rsrc)
+ throws PermissionBackendException, RestApiException, IOException, ConfigInvalidException {
+
+ AccessCheckInput input = new AccessCheckInput();
+ input.ref = refName;
+ input.account = account;
+ input.permission = permission;
+
+ return apply(rsrc, input);
+ }
}
diff --git a/java/com/google/gerrit/server/restapi/project/CheckAccessReadView.java b/java/com/google/gerrit/server/restapi/project/CheckAccessReadView.java
deleted file mode 100644
index 6aaa678..0000000
--- a/java/com/google/gerrit/server/restapi/project/CheckAccessReadView.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2018 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.server.restapi.project;
-
-import com.google.gerrit.extensions.api.config.AccessCheckInfo;
-import com.google.gerrit.extensions.api.config.AccessCheckInput;
-import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.project.ProjectResource;
-import com.google.inject.Inject;
-import java.io.IOException;
-import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.kohsuke.args4j.Option;
-
-public class CheckAccessReadView implements RestReadView<ProjectResource> {
- String refName;
- String account;
- String permission;
-
- @Inject CheckAccess checkAccess;
-
- @Option(name = "--ref", usage = "ref name to check permission for")
- void addOption(String refName) {
- this.refName = refName;
- }
-
- @Option(name = "--account", usage = "account to check acccess for")
- void setAccount(String account) {
- this.account = account;
- }
-
- @Option(name = "--perm", usage = "permission to check; default: read of any ref.")
- void setPermission(String perm) {
- this.permission = perm;
- }
-
- @Override
- public Response<AccessCheckInfo> apply(ProjectResource rsrc)
- throws PermissionBackendException, RestApiException, IOException, ConfigInvalidException {
-
- AccessCheckInput input = new AccessCheckInput();
- input.ref = refName;
- input.account = account;
- input.permission = permission;
-
- return checkAccess.apply(rsrc, input);
- }
-}
diff --git a/java/com/google/gerrit/server/restapi/project/ListProjects.java b/java/com/google/gerrit/server/restapi/project/ListProjects.java
index 5418876..8a2ab0c 100644
--- a/java/com/google/gerrit/server/restapi/project/ListProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListProjects.java
@@ -90,7 +90,11 @@
import org.eclipse.jgit.lib.Repository;
import org.kohsuke.args4j.Option;
-/** List projects visible to the calling user. */
+/**
+ * List projects visible to the calling user.
+ *
+ * <p>This is like {@link QueryProjects} but with a slightly different calling convention.
+ */
public class ListProjects implements RestReadView<TopLevelResource> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
diff --git a/java/com/google/gerrit/server/restapi/project/Module.java b/java/com/google/gerrit/server/restapi/project/Module.java
index ee3914d..70fb6ea 100644
--- a/java/com/google/gerrit/server/restapi/project/Module.java
+++ b/java/com/google/gerrit/server/restapi/project/Module.java
@@ -57,7 +57,7 @@
get(PROJECT_KIND, "access").to(GetAccess.class);
post(PROJECT_KIND, "access").to(SetAccess.class);
put(PROJECT_KIND, "access:review").to(CreateAccessChange.class);
- get(PROJECT_KIND, "check.access").to(CheckAccessReadView.class);
+ get(PROJECT_KIND, "check.access").to(CheckAccess.class);
post(PROJECT_KIND, "check").to(Check.class);
diff --git a/java/com/google/gerrit/server/restapi/project/QueryProjects.java b/java/com/google/gerrit/server/restapi/project/QueryProjects.java
index e4f7df5..a9d818d 100644
--- a/java/com/google/gerrit/server/restapi/project/QueryProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/QueryProjects.java
@@ -36,6 +36,7 @@
import java.util.List;
import org.kohsuke.args4j.Option;
+/** Implements the {@code GET /projects/?query=QUERY} endpoint. */
public class QueryProjects implements RestReadView<TopLevelResource> {
private final ProjectIndexCollection indexes;
private final ProjectQueryBuilder queryBuilder;
diff --git a/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java b/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
index 709facc..45a895a 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
@@ -19,14 +19,17 @@
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.deny;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.permissionKey;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.Sandboxed;
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.entities.AccessSection;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
@@ -36,9 +39,11 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.inject.Inject;
import java.util.List;
+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;
@@ -48,6 +53,7 @@
public class CheckAccessIT extends AbstractDaemonTest {
@Inject private ProjectOperations projectOperations;
@Inject private GroupOperations groupOperations;
+ @Inject private AllProjectsName allProjectsName;
private Project.NameKey normalProject;
private Project.NameKey secretProject;
@@ -391,4 +397,34 @@
assertThat(info.status).isEqualTo(200);
assertThat(info.message).contains("no branches");
}
+
+ @Test
+ @Sandboxed
+ public void noRules() throws Exception {
+ normalProject = projectOperations.newProject().create();
+
+ for (AccessSection section :
+ projectOperations.project(allProjectsName).getProjectConfig().getAccessSections()) {
+ if (!section.getName().startsWith(Constants.R_REFS)) {
+ continue;
+ }
+ for (Permission permission : section.getPermissions()) {
+ projectOperations
+ .project(allProjectsName)
+ .forUpdate()
+ .remove(permissionKey(permission.getName()).ref(section.getName()).build())
+ .update();
+ }
+ }
+ AccessCheckInput input = new AccessCheckInput();
+ input.account = privilegedUser.email();
+ input.permission = Permission.READ;
+ input.ref = "refs/heads/main";
+
+ AccessCheckInfo info = gApi.projects().name(normalProject.get()).checkAccess(input);
+ assertThat(info.status).isEqualTo(403);
+
+ assertThat(info.debugLogs).isNotEmpty();
+ assertThat(info.debugLogs.get(0)).contains("Found no rules");
+ }
}