Move "ref_rights" table into Git
Permissions are stored in the project.config file within the
refs/meta/config branch of each project. This makes the rules
more flexible in the future, as well as adds version control.
For example:
[access "refs/*"]
owner = group tools-owners
[access "refs/heads/*"]
label-Verified = -1..+1 group tools-dev
label-Verified = -1..+1 group tools-owners
label-Code-Review = -2..+2 group tools-owners
submit = group tools-dev
submit = group tools-owners
[access "refs/heads/stable"]
exclusiveGroupPermissions = read create push
read = group Anonymous Users
push = group tools-repo-maintainer
To enable easy remote editing of the configuration rules, the
following access block is added by default to -- All Projects --
and is thus inherited throughout the entire site:
[access "refs/meta/config"]
read = group Project Owners
push = group Project Owners
This configuration section permits any project owner or site
administrator (as they are indirectly always a project owner of
any project) to push changes to the project.config file within
the refs/meta/config branch, updating access (and other project
information) remotely without using the web UI.
Change-Id: Idb56f657a4bf88108ad40bbb19d831e6806b68c5
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
@@ -14,13 +14,16 @@
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import com.google.gerrit.common.data.AccessSection;
|
||||
import com.google.gerrit.common.data.GroupReference;
|
||||
import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.common.data.PermissionRule;
|
||||
import com.google.gerrit.reviewdb.AccountGroup;
|
||||
import com.google.gerrit.reviewdb.ApprovalCategory;
|
||||
import com.google.gerrit.reviewdb.Project;
|
||||
import com.google.gerrit.reviewdb.RefRight;
|
||||
import com.google.gerrit.server.AnonymousUser;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.WildProjectName;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
@@ -28,15 +31,13 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/** Cached information on a project. */
|
||||
public class ProjectState {
|
||||
public interface Factory {
|
||||
ProjectState create(Project project, Collection<RefRight> localRights);
|
||||
ProjectState create(ProjectConfig config);
|
||||
}
|
||||
|
||||
private final AnonymousUser anonymousUser;
|
||||
@@ -44,92 +45,64 @@ public class ProjectState {
|
||||
private final ProjectCache projectCache;
|
||||
private final ProjectControl.AssistedFactory projectControlFactory;
|
||||
|
||||
private final Project project;
|
||||
private final Collection<RefRight> localRights;
|
||||
private final ProjectConfig config;
|
||||
private final Set<AccountGroup.UUID> localOwners;
|
||||
|
||||
private volatile Collection<RefRight> inheritedRights;
|
||||
|
||||
@Inject
|
||||
protected ProjectState(final AnonymousUser anonymousUser,
|
||||
final ProjectCache projectCache,
|
||||
@WildProjectName final Project.NameKey wildProject,
|
||||
final ProjectControl.AssistedFactory projectControlFactory,
|
||||
@Assisted final Project project,
|
||||
@Assisted Collection<RefRight> rights) {
|
||||
@Assisted final ProjectConfig config) {
|
||||
this.anonymousUser = anonymousUser;
|
||||
this.projectCache = projectCache;
|
||||
this.wildProject = wildProject;
|
||||
this.projectControlFactory = projectControlFactory;
|
||||
this.config = config;
|
||||
|
||||
if (wildProject.equals(project.getNameKey())) {
|
||||
rights = new ArrayList<RefRight>(rights);
|
||||
for (Iterator<RefRight> itr = rights.iterator(); itr.hasNext();) {
|
||||
if (!itr.next().getApprovalCategoryId().canBeOnWildProject()) {
|
||||
itr.remove();
|
||||
HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
|
||||
AccessSection all = config.getAccessSection(AccessSection.ALL);
|
||||
if (all != null) {
|
||||
Permission owner = all.getPermission(Permission.OWNER);
|
||||
if (owner != null) {
|
||||
for (PermissionRule rule : owner.getRules()) {
|
||||
GroupReference ref = rule.getGroup();
|
||||
if (ref.getUUID() != null) {
|
||||
groups.add(ref.getUUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
rights = Collections.unmodifiableCollection(rights);
|
||||
}
|
||||
|
||||
this.project = project;
|
||||
this.localRights = rights;
|
||||
|
||||
final HashSet<AccountGroup.UUID> groups = new HashSet<AccountGroup.UUID>();
|
||||
for (final RefRight right : rights) {
|
||||
if (ApprovalCategory.OWN.equals(right.getApprovalCategoryId())
|
||||
&& right.getMaxValue() > 0
|
||||
&& right.getRefPattern().equals(RefRight.ALL)) {
|
||||
groups.add(right.getAccountGroupUUID());
|
||||
}
|
||||
}
|
||||
localOwners = Collections.unmodifiableSet(groups);
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
return getConfig().getProject();
|
||||
}
|
||||
|
||||
public ProjectConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/** Get the rights that pertain only to this project. */
|
||||
public Collection<RefRight> getLocalRights() {
|
||||
return localRights;
|
||||
public Collection<AccessSection> getLocalAccessSections() {
|
||||
return getConfig().getAccessSections();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rights that pertain only to this project.
|
||||
*
|
||||
* @param action the category requested.
|
||||
* @return immutable collection of rights for the requested category.
|
||||
*/
|
||||
public Collection<RefRight> getLocalRights(ApprovalCategory.Id action) {
|
||||
return filter(getLocalRights(), action);
|
||||
}
|
||||
|
||||
/** Get the rights this project inherits from the wild project. */
|
||||
public Collection<RefRight> getInheritedRights() {
|
||||
if (inheritedRights == null) {
|
||||
inheritedRights = computeInheritedRights();
|
||||
}
|
||||
return inheritedRights;
|
||||
}
|
||||
|
||||
void setInheritedRights(Collection<RefRight> all) {
|
||||
inheritedRights = all;
|
||||
}
|
||||
|
||||
private Collection<RefRight> computeInheritedRights() {
|
||||
if (isSpecialWildProject()) {
|
||||
/** Get the rights this project inherits. */
|
||||
public Collection<AccessSection> getInheritedAccessSections() {
|
||||
if (isWildProject()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<RefRight> inherited = new ArrayList<RefRight>();
|
||||
List<AccessSection> inherited = new ArrayList<AccessSection>();
|
||||
Set<Project.NameKey> seen = new HashSet<Project.NameKey>();
|
||||
Project.NameKey parent = project.getParent();
|
||||
Project.NameKey parent = getProject().getParent();
|
||||
|
||||
while (parent != null && seen.add(parent)) {
|
||||
ProjectState s = projectCache.get(parent);
|
||||
if (s != null) {
|
||||
inherited.addAll(s.getLocalRights());
|
||||
inherited.addAll(s.getLocalAccessSections());
|
||||
parent = s.getProject().getParent();
|
||||
} else {
|
||||
break;
|
||||
@@ -138,76 +111,21 @@ public class ProjectState {
|
||||
|
||||
// Wild project is the parent, or the root of the tree
|
||||
if (parent == null) {
|
||||
inherited.addAll(getWildProjectRights());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableCollection(inherited);
|
||||
}
|
||||
|
||||
private Collection<RefRight> getWildProjectRights() {
|
||||
final ProjectState s = projectCache.get(wildProject);
|
||||
return s != null ? s.getLocalRights() : Collections.<RefRight> emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility class that is needed to filter overridden refrights
|
||||
*/
|
||||
private static class Grant {
|
||||
final AccountGroup.Id group;
|
||||
final String pattern;
|
||||
|
||||
private Grant(AccountGroup.Id group, String pattern) {
|
||||
this.group = group;
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
Grant grant = (Grant) o;
|
||||
return group.equals(grant.group) && pattern.equals(grant.pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = group.hashCode();
|
||||
result = 31 * result + pattern.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rights this project has and inherits from the wild project.
|
||||
*
|
||||
* @param action the category requested.
|
||||
* @param dropOverridden whether to remove inherited permissions in case if we have a
|
||||
* local one that matches (action,group,ref)
|
||||
* @return immutable collection of rights for the requested category.
|
||||
*/
|
||||
public Collection<RefRight> getAllRights(ApprovalCategory.Id action, boolean dropOverridden) {
|
||||
Collection<RefRight> rights = new LinkedList<RefRight>(getLocalRights(action));
|
||||
rights.addAll(filter(getInheritedRights(), action));
|
||||
if (dropOverridden) {
|
||||
Set<Grant> grants = new HashSet<Grant>();
|
||||
Iterator<RefRight> iter = rights.iterator();
|
||||
while (iter.hasNext()) {
|
||||
RefRight right = iter.next();
|
||||
|
||||
Grant grant = new Grant(right.getAccountGroupId(), right.getRefPattern());
|
||||
if (grants.contains(grant)) {
|
||||
iter.remove();
|
||||
} else {
|
||||
grants.add(grant);
|
||||
}
|
||||
ProjectState s = projectCache.get(wildProject);
|
||||
if (s != null) {
|
||||
inherited.addAll(s.getLocalAccessSections());
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableCollection(rights);
|
||||
|
||||
return inherited;
|
||||
}
|
||||
|
||||
/** Is this the special wild project which manages inherited rights? */
|
||||
public boolean isSpecialWildProject() {
|
||||
return project.getNameKey().equals(wildProject);
|
||||
/** Get both local and inherited access sections. */
|
||||
public Collection<AccessSection> getAllAccessSections() {
|
||||
List<AccessSection> all = new ArrayList<AccessSection>();
|
||||
all.addAll(getLocalAccessSections());
|
||||
all.addAll(getInheritedAccessSections());
|
||||
return all;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,12 +135,12 @@ public class ProjectState {
|
||||
* that has local owners are returned
|
||||
*/
|
||||
public Set<AccountGroup.UUID> getOwners() {
|
||||
if (!localOwners.isEmpty() || isSpecialWildProject()
|
||||
|| project.getParent() == null) {
|
||||
Project.NameKey parentName = getProject().getParent();
|
||||
if (!localOwners.isEmpty() || parentName == null || isWildProject()) {
|
||||
return localOwners;
|
||||
}
|
||||
|
||||
final ProjectState parent = projectCache.get(project.getParent());
|
||||
ProjectState parent = projectCache.get(parentName);
|
||||
if (parent != null) {
|
||||
return parent.getOwners();
|
||||
}
|
||||
@@ -238,12 +156,22 @@ public class ProjectState {
|
||||
* assigned for one of the parent projects (the inherited owners).
|
||||
*/
|
||||
public Set<AccountGroup.UUID> getAllOwners() {
|
||||
final HashSet<AccountGroup.UUID> owners = new HashSet<AccountGroup.UUID>();
|
||||
for (final RefRight right : getAllRights(ApprovalCategory.OWN, true)) {
|
||||
if (right.getMaxValue() > 0 && right.getRefPattern().equals(RefRight.ALL)) {
|
||||
owners.add(right.getAccountGroupUUID());
|
||||
HashSet<AccountGroup.UUID> owners = new HashSet<AccountGroup.UUID>();
|
||||
owners.addAll(localOwners);
|
||||
|
||||
Set<Project.NameKey> seen = new HashSet<Project.NameKey>();
|
||||
Project.NameKey parent = getProject().getParent();
|
||||
|
||||
while (parent != null && seen.add(parent)) {
|
||||
ProjectState s = projectCache.get(parent);
|
||||
if (s != null) {
|
||||
owners.addAll(s.localOwners);
|
||||
parent = s.getProject().getParent();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(owners);
|
||||
}
|
||||
|
||||
@@ -255,20 +183,7 @@ public class ProjectState {
|
||||
return projectControlFactory.create(user, this);
|
||||
}
|
||||
|
||||
private static Collection<RefRight> filter(Collection<RefRight> all,
|
||||
ApprovalCategory.Id actionId) {
|
||||
if (all.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final Collection<RefRight> mine = new ArrayList<RefRight>(all.size());
|
||||
for (final RefRight right : all) {
|
||||
if (right.getApprovalCategoryId().equals(actionId)) {
|
||||
mine.add(right);
|
||||
}
|
||||
}
|
||||
if (mine.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableCollection(mine);
|
||||
private boolean isWildProject() {
|
||||
return wildProject.equals(getProject().getNameKey());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user