SetAccess: Fix granting the CREATE_GROUP capability to a second group

If one group had the global CREATE_GROUP capability assigned and a
caller attempted to grant the global CREATE_GROUP capability to another
group, using the SetAccess REST endpoint, the call failed with an
IllegalArgumentException [1].

A new group is created by creating a new group ref in the All-Users
repository. Whether creating a ref is possible is controlled by the
CREATE permission on the ref. Hence for group refs we check for a CREATE
permission on refs/groups/*. Since this is not obvious for most users we
also have a global CREATE_GROUP capability which can be assigned on the
All-Projects project. In fact users can only grant the global
CREATE_GROUP capability, but not the CREATE permission on refs/groups/*
in All-Users. The CREATE permission on refs/groups/* in All-Users is
automatically kept in sync with the global CREATE_GROUP capability and
cannot be changed manually. The code to do this syncing is
CreateGroupPermissionSyncer.

CreateGroupPermissionSyncer had a bug when it synced the global
CREATE_GROUP capability to group ref CREATE permissions, if a group ref
CREATE permission already existed:

1. The CREATE_GROUP capability is assigned to group A.
2. CreateGroupPermissionSyncer syncs the permissions and sets the group
   ref CREATE permission for group A.
3. The CREATE_GROUP capability is assigned to group B.
4. CreateGroupPermissionSyncer tries to sync the permissions and set the
   group ref CREATE permission for group A and group B, but fails since
   the group ref CREATE permission already exists for group A.

Since the group ref CREATE permissions are exclusively managed by Gerrit
we always want to overwrite them, when the global CREATE_GROUP
capability changes. To fix step 4. remove the group ref CREATE
permission for group A before setting it for group A and B.

[1]
java.lang.IllegalArgumentException
        at com.google.gerrit.common.data.AccessSection.addPermission(AccessSection.java:114)
        at com.google.gerrit.server.CreateGroupPermissionSyncer.syncIfNeeded(CreateGroupPermissionSyncer.java:119)
        at com.google.gerrit.server.restapi.project.SetAccess.apply(SetAccess.java:129)
        at com.google.gerrit.server.restapi.project.SetAccess.apply(SetAccess.java:44)
        at com.google.gerrit.httpd.restapi.RestApiServlet.lambda$invokeRestModifyViewWithRetry$4(RestApiServlet.java:740)
        at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
        at com.github.rholder.retry.Retryer.call(Retryer.java:160)
        at com.google.gerrit.server.update.RetryHelper.executeWithTimeoutCount(RetryHelper.java:417)
        at com.google.gerrit.server.update.RetryHelper.executeWithAttemptAndTimeoutCount(RetryHelper.java:368)
        at com.google.gerrit.server.update.RetryHelper.execute(RetryHelper.java:271)
        at com.google.gerrit.httpd.restapi.RestApiServlet.invokeRestEndpointWithRetry(RestApiServlet.java:820)
        at com.google.gerrit.httpd.restapi.RestApiServlet.invokeRestModifyViewWithRetry(RestApiServlet.java:735)
        at com.google.gerrit.httpd.restapi.RestApiServlet.service(RestApiServlet.java:511)
        ...

Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Id064b7ce7599048ca2cd81c8ccd3dfd8704909ce
2 files changed
tree: 2ad191966791c97f94e710475933fb2e436e7d8a
  1. .settings/
  2. antlr3/
  3. contrib/
  4. Documentation/
  5. e2e-tests/
  6. java/
  7. javatests/
  8. lib/
  9. modules/
  10. plugins/
  11. polygerrit-ui/
  12. prolog/
  13. prologtests/
  14. proto/
  15. resources/
  16. tools/
  17. webapp/
  18. .bazelignore
  19. .bazelproject
  20. .bazelrc
  21. .bazelversion
  22. .editorconfig
  23. .git-blame-ignore-revs
  24. .gitignore
  25. .gitmodules
  26. .gitreview
  27. .mailmap
  28. .pydevproject
  29. BUILD
  30. COPYING
  31. INSTALL
  32. Jenkinsfile
  33. package.json
  34. README.md
  35. SUBMITTING_PATCHES
  36. version.bzl
  37. WORKSPACE
README.md

Gerrit Code Review

Gerrit is a code review and project management tool for Git based projects.

Build Status

Objective

Gerrit makes reviews easier by showing changes in a side-by-side display, and allowing inline comments to be added by any reviewer.

Gerrit simplifies Git based project maintainership by permitting any authorized user to submit changes to the master Git repository, rather than requiring all approved changes to be merged in by hand by the project maintainer.

Documentation

For information about how to install and use Gerrit, refer to the documentation.

Source

Our canonical Git repository is located on googlesource.com. There is a mirror of the repository on Github.

Reporting bugs

Please report bugs on the issue tracker.

Contribute

Gerrit is the work of hundreds of contributors. We appreciate your help!

Please read the contribution guidelines.

Note that we do not accept Pull Requests via the Github mirror.

Getting in contact

The Developer Mailing list is repo-discuss on Google Groups.

License

Gerrit is provided under the Apache License 2.0.

Build

Install Bazel and run the following:

    git clone --recurse-submodules https://gerrit.googlesource.com/gerrit
    cd gerrit && bazel build release

Install binary packages (Deb/Rpm)

The instruction how to configure GerritForge/BinTray repositories is here

On Debian/Ubuntu run:

    apt-get update & apt-get install gerrit=<version>-<release>

NOTE: release is a counter that starts with 1 and indicates the number of packages that have been released with the same version of the software.

On CentOS/RedHat run:

    yum clean all && yum install gerrit-<version>[-<release>]

On Fedora run:

    dnf clean all && dnf install gerrit-<version>[-<release>]

Use pre-built Gerrit images on Docker

Docker images of Gerrit are available on DockerHub

To run a CentOS 7 based Gerrit image:

    docker run -p 8080:8080 gerritforge/gerrit-centos7[:version]

To run a Ubuntu 15.04 based Gerrit image:

    docker run -p 8080:8080 gerritforge/gerrit-ubuntu15.04[:version]

NOTE: release is optional. Last released package of the version is installed if the release number is omitted.