Fix: Permission.PUSH_MERGE checking for push bypassing Gerrit

Gerrit always check Permission.PUSH_MERGE on branches
starting with 'refs/for' even for the push bypassing
Gerrit, e.g. creating a new branch using a merge with
command like:
   git push origin   <merge-sha1>:refs/heads/<new-branch-name>
As this is not for review, the `Push Merge` is expected
to exist on 'refs/heads/<new-branch-name>', not on
'refs/for/refs/heads/<new-branch-name>'.

This commit fix it to avoid user confusion when granting
access to 'refs/heads/*' doesn't allow them to push
directly any merge commits bypassing the code review.

Issue: 1072
Change-Id: Ib76d72a3d6435429b14f696f2833ca5cd847ba63
This commit is contained in:
Bruce Zu 2013-08-28 14:03:22 +08:00
parent 2e0f89d814
commit f6159bed86
5 changed files with 37 additions and 12 deletions

View File

@ -609,12 +609,11 @@ push to happen. Some projects wish to restrict merges to being created
by Gerrit. By granting `Push` without `Push Merge Commit`, the only
merges that enter the system will be those created by Gerrit.
The reference name connected to a `Push Merge Commit` entry must always
be prefixed with `refs/for/`, for example `refs/for/refs/heads/BRANCH`.
This applies even for an entry that complements a `Push` entry for
`refs/heads/BRANCH` that allows direct pushes of non-merge commits, and
the intention of the `Push Merge Commit` entry is to allow direct pushes
of merge commits.
For pushing a merge commit for review, the reference name connected to
a `Push Merge Commit` entry must be prefixed with `refs/for/`,
for example `refs/for/refs/heads/BRANCH`. For pushing a merge commit
directly into the repository bypassing review, the reference name
must be `refs/heads/BRANCH`.
[[category_push_annotated]]

View File

@ -1986,7 +1986,8 @@ public class ReceiveCommits {
if (ctl.canForgeAuthor()
&& ctl.canForgeCommitter()
&& ctl.canForgeGerritServerIdentity()
&& ctl.canUploadMerges()
&& (MagicBranch.isForReview(cmd.getRefName()) ? ctl.canUploadMerges()
: ctl.canPushMerges())
&& !projectControl.getProjectState().isUseSignedOffBy()
&& Iterables.isEmpty(rejectCommits)
&& !GitRepositoryManager.REF_CONFIG.equals(ctl.getRefName())

View File

@ -355,10 +355,20 @@ public class CommitValidators {
@Override
public List<CommitValidationMessage> onCommitReceived(
CommitReceivedEvent receiveEvent) throws CommitValidationException {
if (receiveEvent.commit.getParentCount() > 1
&& !refControl.canUploadMerges()) {
throw new CommitValidationException("you are not allowed to upload merges");
if (receiveEvent.commit.getParentCount() > 1) {
if (MagicBranch.isForReview(receiveEvent.command.getRefName())) {
if (!refControl.canUploadMerges()) {
throw new CommitValidationException(
"you are not allowed to upload merges for review");
}
} else {
if (!refControl.canPushMerges()) {
throw new CommitValidationException(
"you are not allowed to push merges directly bypassing code review");
}
}
}
return Collections.<CommitValidationMessage> emptyList();
}
}

View File

@ -147,7 +147,17 @@ public class RefControl {
&& canWrite();
}
/** @return true if this user can submit merge patch sets to this ref */
/**
* @return true if this user can push merge commits directly bypassing code
* review to this ref.
*/
public boolean canPushMerges() {
return projectControl.controlForRef(getRefName()).canPerform(
Permission.PUSH_MERGE)
&& canWrite();
}
/** @return true if this user can upload merge commits to this ref for review */
public boolean canUploadMerges() {
return projectControl.controlForRef("refs/for/" + getRefName())
.canPerform(Permission.PUSH_MERGE)

View File

@ -51,6 +51,11 @@ public final class MagicBranch {
|| refName.startsWith(NEW_CHANGE);
}
/** Checks if the supplied ref name is a magic branch for review */
public static boolean isForReview(String refName) {
return isMagicBranch(refName);
}
/** Returns the ref name prefix for a magic branch, <code>null</code> if the branch is not magic */
public static String getMagicRefNamePrefix(String refName) {
if (refName.startsWith(NEW_DRAFT_CHANGE)) {