Add ADD_PATCH_SET logic to lock patch sets

I've added a new permission to distinguish between creating a change and
adding new patch sets. This is intended for projects that want to
restrict the upload of new patch sets to the change owner (or any other
group).

Change-Id: If9f9f7ed0f0890fb4b854d0bf71e546ebe43ef96
This commit is contained in:
Patrick Hiesel
2016-06-14 12:34:51 +02:00
parent a008aa9428
commit 26518696c0
15 changed files with 324 additions and 16 deletions

View File

@@ -564,6 +564,19 @@ that would otherwise be used. Or it may give permission to upload
new changes for code review, this depends on which namespace the new changes for code review, this depends on which namespace the
permission is granted to. permission is granted to.
[[category_push_patch_set]]
=== Push Patch Set
This category controls which users are allowed to upload new patch sets to
existing changes. Irrespective of this permission, change owners are always
allowed to upload new patch sets for their changes. This permission needs to be
set on `refs/for/*`.
The absence of this permission will prevent users from uploading a
patch set to a change they do not own. By default, this permission is granted to
`Registered Users` on `refs/for/*` allowing all registered users to upload a new
patch set to any change on that ref.
[[category_push_direct]] [[category_push_direct]]
==== Direct Push ==== Direct Push

View File

@@ -741,6 +741,12 @@ public abstract class AbstractDaemonTest {
protected PermissionRule block(String permission, AccountGroup.UUID id, String ref) protected PermissionRule block(String permission, AccountGroup.UUID id, String ref)
throws Exception { throws Exception {
return block(permission, id, ref, project);
}
protected PermissionRule block(String permission,
AccountGroup.UUID id, String ref, Project.NameKey project)
throws Exception {
ProjectConfig cfg = projectCache.checkedGet(project).getConfig(); ProjectConfig cfg = projectCache.checkedGet(project).getConfig();
PermissionRule rule = Util.block(cfg, permission, id, ref); PermissionRule rule = Util.block(cfg, permission, id, ref);
saveProjectConfig(project, cfg); saveProjectConfig(project, cfg);

View File

@@ -66,6 +66,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.change.ChangeResource; import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.config.AnonymousCowardNameProvider; import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
@@ -1506,6 +1507,7 @@ public class ChangeIT extends AbstractDaemonTest {
db, admin.getIdent(), adminTestRepo); db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/for/master"); PushOneCommit.Result r1 = push.to("refs/for/master");
r1.assertOkStatus(); r1.assertOkStatus();
// Amend draft as admin // Amend draft as admin
PushOneCommit.Result r2 = amendChange( PushOneCommit.Result r2 = amendChange(
r1.getChangeId(), "refs/drafts/master", admin, adminTestRepo); r1.getChangeId(), "refs/drafts/master", admin, adminTestRepo);
@@ -1518,10 +1520,154 @@ public class ChangeIT extends AbstractDaemonTest {
// Amend change as user // Amend change as user
PushOneCommit.Result r3 = amendChange( PushOneCommit.Result r3 = amendChange(
r1.getChangeId(), "refs/for/master", user, userTestRepo); r1.getChangeId(), "refs/for/master", user, userTestRepo);
r3.assertErrorStatus("cannot replace " r3.assertErrorStatus("cannot add patch set to "
+ r3.getChange().change().getChangeId() + "."); + r3.getChange().change().getChangeId() + ".");
} }
@Test
public void createNewPatchSetWithoutPermission() throws Exception {
// Create new project with clean permissions
Project.NameKey p = createProject("addPatchSet1");
// Clone separate repositories of the same project as admin and as user
TestRepository<InMemoryRepository> adminTestRepo =
cloneProject(p, admin);
TestRepository<InMemoryRepository> userTestRepo =
cloneProject(p, user);
// Block default permission
block(Permission.ADD_PATCH_SET,
REGISTERED_USERS, "refs/for/*", p);
// Create change as admin
PushOneCommit push = pushFactory.create(
db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/for/master");
r1.assertOkStatus();
// Fetch change
GitUtil.fetch(userTestRepo, r1.getPatchSet().getRefName() + ":ps");
userTestRepo.reset("ps");
// Amend change as user
PushOneCommit.Result r2 =
amendChange(r1.getChangeId(), "refs/for/master", user, userTestRepo);
r2.assertErrorStatus("cannot add patch set to "
+ r1.getChange().getId().id + ".");
}
@Test
public void createNewSetPatchWithPermission() throws Exception {
// Clone separate repositories of the same project as admin and as user
TestRepository<?> adminTestRepo = cloneProject(project, admin);
TestRepository<?> userTestRepo = cloneProject(project, user);
// Create change as admin
PushOneCommit push = pushFactory.create(
db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/for/master");
r1.assertOkStatus();
// Fetch change
GitUtil.fetch(userTestRepo, r1.getPatchSet().getRefName() + ":ps");
userTestRepo.reset("ps");
// Amend change as user
PushOneCommit.Result r2 = amendChange(
r1.getChangeId(), "refs/for/master", user, userTestRepo);
r2.assertOkStatus();
}
@Test
public void createNewPatchSetAsOwnerWithoutPermission() throws Exception {
// Create new project with clean permissions
Project.NameKey p = createProject("addPatchSet2");
// Clone separate repositories of the same project as admin and as user
TestRepository<?> adminTestRepo = cloneProject(project, admin);
// Block default permission
block(Permission.ADD_PATCH_SET, REGISTERED_USERS, "refs/for/*", p);
// Create change as admin
PushOneCommit push =
pushFactory.create(db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/for/master");
r1.assertOkStatus();
// Fetch change
GitUtil.fetch(adminTestRepo, r1.getPatchSet().getRefName() + ":ps");
adminTestRepo.reset("ps");
// Amend change as admin
PushOneCommit.Result r2 = amendChange(
r1.getChangeId(), "refs/for/master", admin, adminTestRepo);
r2.assertOkStatus();
}
@Test
public void createNewPatchSetAsReviewerOnDraftChange() throws Exception {
// Clone separate repositories of the same project as admin and as user
TestRepository<?> adminTestRepo = cloneProject(project, admin);
TestRepository<?> userTestRepo = cloneProject(project, user);
// Create change as admin
PushOneCommit push = pushFactory.create(
db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/drafts/master");
r1.assertOkStatus();
// Add user as reviewer
AddReviewerInput in = new AddReviewerInput();
in.reviewer = user.email;
gApi.changes()
.id(r1.getChangeId())
.addReviewer(in);
// Fetch change
GitUtil.fetch(userTestRepo, r1.getPatchSet().getRefName() + ":ps");
userTestRepo.reset("ps");
// Amend change as user
PushOneCommit.Result r2 = amendChange(
r1.getChangeId(), "refs/for/master", user, userTestRepo);
r2.assertOkStatus();
}
@Test
public void createNewDraftPatchSetOnDraftChange() throws Exception {
// Create new project with clean permissions
Project.NameKey p = createProject("addPatchSet4");
// Clone separate repositories of the same project as admin and as user
TestRepository<?> adminTestRepo = cloneProject(p, admin);
TestRepository<?> userTestRepo = cloneProject(p, user);
// Block default permission
block(Permission.ADD_PATCH_SET, REGISTERED_USERS, "refs/for/*", p);
// Create change as admin
PushOneCommit push = pushFactory.create(
db, admin.getIdent(), adminTestRepo);
PushOneCommit.Result r1 = push.to("refs/drafts/master");
r1.assertOkStatus();
// Add user as reviewer
AddReviewerInput in = new AddReviewerInput();
in.reviewer = user.email;
gApi.changes()
.id(r1.getChangeId())
.addReviewer(in);
// Fetch change
GitUtil.fetch(userTestRepo, r1.getPatchSet().getRefName() + ":ps");
userTestRepo.reset("ps");
// Amend change as user
PushOneCommit.Result r2 = amendChange(
r1.getChangeId(), "refs/drafts/master", user, userTestRepo);
r2.assertErrorStatus("cannot add patch set to "
+ r1.getChange().getId().id + ".");
}
private static Iterable<Account.Id> getReviewers( private static Iterable<Account.Id> getReviewers(
Collection<AccountInfo> r) { Collection<AccountInfo> r) {
return Iterables.transform(r, new Function<AccountInfo, Account.Id>() { return Iterables.transform(r, new Function<AccountInfo, Account.Id>() {

View File

@@ -16,6 +16,7 @@ package com.google.gerrit.acceptance.edit;
import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
@@ -29,6 +30,7 @@ import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.TestProjectInput; import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.common.RawInputUtil; import com.google.gerrit.common.RawInputUtil;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.InheritableBoolean; import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.ListChangesOption; import com.google.gerrit.extensions.client.ListChangesOption;
@@ -42,6 +44,7 @@ import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.ChangeEdits.EditMessage; import com.google.gerrit.server.change.ChangeEdits.EditMessage;
import com.google.gerrit.server.change.ChangeEdits.Post; import com.google.gerrit.server.change.ChangeEdits.Post;
@@ -61,6 +64,8 @@ import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.apache.commons.codec.binary.StringUtils; import org.apache.commons.codec.binary.StringUtils;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
@@ -768,6 +773,28 @@ public class ChangeEditIT extends AbstractDaemonTest {
assertThat(diff.diffHeader.get(0)).contains(FILE_NAME); assertThat(diff.diffHeader.get(0)).contains(FILE_NAME);
} }
@Test
public void createEditWithoutPushPatchSetPermission() throws Exception {
// Create new project with clean permissions
Project.NameKey p = createProject("addPatchSetEdit");
// Clone repository as user
TestRepository<InMemoryRepository> userTestRepo =
cloneProject(p, user);
// Block default permission
block(Permission.ADD_PATCH_SET, REGISTERED_USERS, "refs/for/*", p);
// Create change as user
PushOneCommit push = pushFactory.create(
db, user.getIdent(), userTestRepo);
PushOneCommit.Result r1 = push.to("refs/for/master");
r1.assertOkStatus();
// Try to create edit as admin
assertThat(modifier.createEdit(r1.getChange().change(),
r1.getPatchSet())).isEqualTo(RefUpdate.Result.REJECTED);
}
private List<ChangeInfo> queryEdits() throws Exception { private List<ChangeInfo> queryEdits() throws Exception {
return query("project:{" + project.get() + "} has:edit"); return query("project:{" + project.get() + "} has:edit");
} }

View File

@@ -429,7 +429,8 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
PushOneCommit.SUBJECT, "b.txt", "anotherContent", r.getChangeId()); PushOneCommit.SUBJECT, "b.txt", "anotherContent", r.getChangeId());
revision(r).review(new ReviewInput().label("Patch-Set-Lock", 1)); revision(r).review(new ReviewInput().label("Patch-Set-Lock", 1));
r = push.to("refs/for/master"); r = push.to("refs/for/master");
r.assertErrorStatus("cannot replace " + r.getChange().change().getChangeId() r.assertErrorStatus("cannot add patch set to "
+ r.getChange().change().getChangeId()
+ ". Change is patch set locked."); + ". Change is patch set locked.");
} }

View File

@@ -241,7 +241,6 @@ public class VisibleRefFilterIT extends AbstractDaemonTest {
setApiUser(admin); setApiUser(admin);
editModifier.createEdit(c, ps1); editModifier.createEdit(c, ps1);
setApiUser(user); setApiUser(user);
editModifier.createEdit(c, ps1);
assertRefs( assertRefs(
// Change 1 is visible due to accessDatabase capability, even though // Change 1 is visible due to accessDatabase capability, even though
@@ -255,8 +254,7 @@ public class VisibleRefFilterIT extends AbstractDaemonTest {
// See comment in subsetOfBranchesVisibleNotIncludingHead. // See comment in subsetOfBranchesVisibleNotIncludingHead.
"refs/tags/master-tag", "refs/tags/master-tag",
// All edits are visible due to accessDatabase capability. // All edits are visible due to accessDatabase capability.
"refs/users/00/1000000/edit-" + c1.get() + "/1", "refs/users/00/1000000/edit-" + c1.get() + "/1");
"refs/users/01/1000001/edit-" + c1.get() + "/1");
} finally { } finally {
removeGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE); removeGlobalCapabilities(REGISTERED_USERS, GlobalCapability.ACCESS_DATABASE);
} }

View File

@@ -120,6 +120,7 @@ addPermission = Add Permission ...
# Permission Names # Permission Names
permissionNames = \ permissionNames = \
abandon, \ abandon, \
addPatchSet, \
create, \ create, \
deleteDrafts, \ deleteDrafts, \
editHashtags, \ editHashtags, \
@@ -141,6 +142,7 @@ permissionNames = \
viewDrafts viewDrafts
abandon = Abandon abandon = Abandon
addPatchSet = Add Patch Set
create = Create Reference create = Create Reference
deleteDrafts = Delete Drafts deleteDrafts = Delete Drafts
editHashtags = Edit Hashtags editHashtags = Edit Hashtags

View File

@@ -20,6 +20,7 @@ import static com.google.gerrit.server.notedb.ReviewerStateInternal.CC;
import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER; import static com.google.gerrit.server.notedb.ReviewerStateInternal.REVIEWER;
import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.ChangeMessage; import com.google.gerrit.reviewdb.client.ChangeMessage;
@@ -196,7 +197,7 @@ public class PatchSetInserter extends BatchUpdate.Op {
@Override @Override
public void updateRepo(RepoContext ctx) public void updateRepo(RepoContext ctx)
throws ResourceConflictException, IOException { throws AuthException, ResourceConflictException, IOException, OrmException {
init(); init();
validate(ctx); validate(ctx);
ctx.addRefUpdate(new ReceiveCommand(ObjectId.zeroId(), ctx.addRefUpdate(new ReceiveCommand(ObjectId.zeroId(),
@@ -288,10 +289,15 @@ public class PatchSetInserter extends BatchUpdate.Op {
} }
private void validate(RepoContext ctx) private void validate(RepoContext ctx)
throws ResourceConflictException, IOException { throws AuthException, ResourceConflictException, IOException,
OrmException {
CommitValidators cv = commitValidatorsFactory.create( CommitValidators cv = commitValidatorsFactory.create(
origCtl.getRefControl(), sshInfo, ctx.getRepository()); origCtl.getRefControl(), sshInfo, ctx.getRepository());
if (!origCtl.canAddPatchSet(ctx.getDb())) {
throw new AuthException("cannot add patch set");
}
String refName = getPatchSetId().toRefName(); String refName = getPatchSetId().toRefName();
CommitReceivedEvent event = new CommitReceivedEvent( CommitReceivedEvent event = new CommitReceivedEvent(
new ReceiveCommand( new ReceiveCommand(

View File

@@ -35,7 +35,9 @@ import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.index.change.ChangeIndexer; import com.google.gerrit.server.index.change.ChangeIndexer;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -96,18 +98,21 @@ public class ChangeEditModifier {
private final ChangeIndexer indexer; private final ChangeIndexer indexer;
private final Provider<ReviewDb> reviewDb; private final Provider<ReviewDb> reviewDb;
private final Provider<CurrentUser> currentUser; private final Provider<CurrentUser> currentUser;
private final ChangeControl.GenericFactory changeControlFactory;
@Inject @Inject
ChangeEditModifier(@GerritPersonIdent PersonIdent gerritIdent, ChangeEditModifier(@GerritPersonIdent PersonIdent gerritIdent,
GitRepositoryManager gitManager, GitRepositoryManager gitManager,
ChangeIndexer indexer, ChangeIndexer indexer,
Provider<ReviewDb> reviewDb, Provider<ReviewDb> reviewDb,
Provider<CurrentUser> currentUser) { Provider<CurrentUser> currentUser,
ChangeControl.GenericFactory changeControlFactory) {
this.gitManager = gitManager; this.gitManager = gitManager;
this.indexer = indexer; this.indexer = indexer;
this.reviewDb = reviewDb; this.reviewDb = reviewDb;
this.currentUser = currentUser; this.currentUser = currentUser;
this.tz = gerritIdent.getTimeZone(); this.tz = gerritIdent.getTimeZone();
this.changeControlFactory = changeControlFactory;
} }
/** /**
@@ -127,10 +132,19 @@ public class ChangeEditModifier {
if (!currentUser.get().isIdentifiedUser()) { if (!currentUser.get().isIdentifiedUser()) {
throw new AuthException("Authentication required"); throw new AuthException("Authentication required");
} }
IdentifiedUser me = currentUser.get().asIdentifiedUser(); IdentifiedUser me = currentUser.get().asIdentifiedUser();
String refPrefix = RefNames.refsEditPrefix(me.getAccountId(), change.getId()); String refPrefix = RefNames.refsEditPrefix(me.getAccountId(), change.getId());
try {
ChangeControl c =
changeControlFactory.controlFor(reviewDb.get(), change, me);
if (!c.canAddPatchSet(reviewDb.get())) {
return RefUpdate.Result.REJECTED;
}
} catch (NoSuchChangeException e) {
return RefUpdate.Result.NO_CHANGE;
}
try (Repository repo = gitManager.openRepository(change.getProject())) { try (Repository repo = gitManager.openRepository(change.getProject())) {
Map<String, Ref> refs = repo.getRefDatabase().getRefs(refPrefix); Map<String, Ref> refs = repo.getRefDatabase().getRefs(refPrefix);
if (!refs.isEmpty()) { if (!refs.isEmpty()) {

View File

@@ -2016,7 +2016,8 @@ public class ReceiveCommits {
if (changeCtl.isPatchSetLocked(db)) { if (changeCtl.isPatchSetLocked(db)) {
locked = ". Change is patch set locked."; locked = ". Change is patch set locked.";
} }
reject(inputCommand, "cannot replace " + ontoChange + locked); reject(inputCommand, "cannot add patch set to "
+ ontoChange + locked);
return false; return false;
} else if (notes.getChange().getStatus().isClosed()) { } else if (notes.getChange().getStatus().isClosed()) {
reject(inputCommand, "change " + ontoChange + " closed"); reject(inputCommand, "change " + ontoChange + " closed");

View File

@@ -314,11 +314,16 @@ public class ChangeControl {
} }
/** Can this user add a patch set to this change? */ /** Can this user add a patch set to this change? */
public boolean canAddPatchSet(ReviewDb db) public boolean canAddPatchSet(ReviewDb db) throws OrmException {
throws OrmException { if (!getRefControl().canUpload()
return getRefControl().canUpload() || isPatchSetLocked(db)
&& !isPatchSetLocked(db) || !isPatchVisible(patchSetUtil.current(db, notes), db)) {
&& isPatchVisible(patchSetUtil.current(db, notes), db); return false;
}
if (isOwner()) {
return true;
}
return getRefControl().canAddPatchSet();
} }
/** Is the current patch set locked against state changes? */ /** Is the current patch set locked against state changes? */

View File

@@ -150,6 +150,13 @@ public class RefControl {
&& canWrite(); && canWrite();
} }
/** @return true if this user can add a new patch set to this ref */
public boolean canAddPatchSet() {
return projectControl.controlForRef("refs/for/" + getRefName())
.canPerform(Permission.ADD_PATCH_SET)
&& canWrite();
}
/** @return true if this user can submit merge patch sets to this ref */ /** @return true if this user can submit merge patch sets to this ref */
public boolean canUploadMerges() { public boolean canUploadMerges() {
return projectControl.controlForRef("refs/for/" + getRefName()) return projectControl.controlForRef("refs/for/" + getRefName())

View File

@@ -138,10 +138,12 @@ public class AllProjectsCreator {
AccessSection heads = config.getAccessSection(AccessSection.HEADS, true); AccessSection heads = config.getAccessSection(AccessSection.HEADS, true);
AccessSection tags = config.getAccessSection("refs/tags/*", true); AccessSection tags = config.getAccessSection("refs/tags/*", true);
AccessSection meta = config.getAccessSection(RefNames.REFS_CONFIG, true); AccessSection meta = config.getAccessSection(RefNames.REFS_CONFIG, true);
AccessSection refsFor = config.getAccessSection("refs/for/*", true);
AccessSection magic = config.getAccessSection("refs/for/" + AccessSection.ALL, true); AccessSection magic = config.getAccessSection("refs/for/" + AccessSection.ALL, true);
grant(config, cap, GlobalCapability.ADMINISTRATE_SERVER, admin); grant(config, cap, GlobalCapability.ADMINISTRATE_SERVER, admin);
grant(config, all, Permission.READ, admin, anonymous); grant(config, all, Permission.READ, admin, anonymous);
grant(config, refsFor, Permission.ADD_PATCH_SET, registered);
if (batch != null) { if (batch != null) {
Permission priority = cap.getPermission(GlobalCapability.PRIORITY, true); Permission priority = cap.getPermission(GlobalCapability.PRIORITY, true);

View File

@@ -33,7 +33,7 @@ import java.util.List;
/** A version of the database schema. */ /** A version of the database schema. */
public abstract class SchemaVersion { public abstract class SchemaVersion {
/** The current schema version. */ /** The current schema version. */
public static final Class<Schema_127> C = Schema_127.class; public static final Class<Schema_128> C = Schema_128.class;
public static int getBinaryVersion() { public static int getBinaryVersion() {
return guessVersion(C); return guessVersion(C);

View File

@@ -0,0 +1,80 @@
// 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.server.schema;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.schema.AclUtil.grant;
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.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import java.io.IOException;
public class Schema_128 extends SchemaVersion {
private static final String COMMIT_MSG =
"Add addPatchSet permission to all projects";
private final GitRepositoryManager repoManager;
private final AllProjectsName allProjectsName;
private final PersonIdent serverUser;
@Inject
Schema_128(Provider<Schema_126> prior,
GitRepositoryManager repoManager,
AllProjectsName allProjectsName,
@GerritPersonIdent PersonIdent serverUser) {
super(prior);
this.repoManager = repoManager;
this.allProjectsName = allProjectsName;
this.serverUser = serverUser;
}
@Override
protected void migrateData(ReviewDb db, UpdateUI ui) throws OrmException {
try (Repository git = repoManager.openRepository(allProjectsName);
MetaDataUpdate md = new MetaDataUpdate(GitReferenceUpdated.DISABLED,
allProjectsName, git)) {
ProjectConfig config = ProjectConfig.read(md);
GroupReference registered = SystemGroupBackend.getGroup(REGISTERED_USERS);
AccessSection refsFor = config.getAccessSection("refs/for/*", true);
grant(config, refsFor, Permission.ADD_PATCH_SET,
false, false, registered);
md.getCommitBuilder().setAuthor(serverUser);
md.getCommitBuilder().setCommitter(serverUser);
md.setMessage(COMMIT_MSG);
config.commit(md);
} catch (ConfigInvalidException | IOException ex) {
throw new OrmException(ex);
}
}
}