Make permissions for tag creation consistent

For each tag type you need a special permission for the tag creation:
- Lightweight tags require 'Create Reference'
- Annontated tags require 'Push Annotated Tags'
- Signed tags require 'Push Signed Tags'

When creating a tag by push there are 2 cases:
1. The commit to which the tag points already exists in Gerrit
   (it is reachable from any branch/tag that is readable by the
   calling user)
2. The commit to which the tag points is new
   (it is not reachable from any branch/tag that is readable by the
   calling user)

So far the permissions that were required to push a tag on a new
commit were inconsistent:
- For lightweight tags we required 'Push' in addition to 'Create
  Reference'
- For annotated/signed tags 'Push Annotated Tags'/'Push Signed Tags'
  were sufficient.

Due to this it was not possible to allow pushing of annotated/signed
tags for existing commits, but not for new commits.

Change the behaviour for annotated/signed tags so that it's consistent
with the behaviour for lightweight tags and require 'Push' in addition
to 'Push Annotated Tags'/'Push Signed Tags', if the tag points to a
new commit.

We may consider renaming 'Push Annotated Tags'/'Push Signed Tags' to
'Create Annotated Tags'/'Create Signed Tags' later.

Add tests for the tag creation by push that cover lightweight and
annotated tags on existing and new commits. Tests for signed tags may
be added later.

Change-Id: I1094a2be4871e16239b6a6daefc537ffc77af3bf
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2016-09-02 14:37:17 +02:00
parent 86cdf1b494
commit 94db6b6e84
6 changed files with 226 additions and 12 deletions

View File

@@ -807,6 +807,19 @@ public abstract class AbstractDaemonTest {
}
}
protected void removePermission(String permission, Project.NameKey project,
String ref) throws IOException, ConfigInvalidException {
try (MetaDataUpdate md = metaDataUpdateFactory.create(project)) {
md.setMessage(String.format("Remove %s on %s", permission, ref));
ProjectConfig config = ProjectConfig.read(md);
AccessSection s = config.getAccessSection(ref, true);
Permission p = s.getPermission(permission, true);
p.getRules().clear();
config.commit(md);
projectCache.evict(config.getProject());
}
}
protected void blockRead(String ref) throws Exception {
block(Permission.READ, REGISTERED_USERS, ref);
}

View File

@@ -28,12 +28,15 @@ import com.jcraft.jsch.Session;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.TagCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchResult;
@@ -137,6 +140,16 @@ public class GitUtil {
return cloneProject(project, sshSession.getUrl() + "/" + project.get());
}
public static Ref createAnnotatedTag(TestRepository<?> testRepo, String name,
PersonIdent tagger) throws GitAPIException {
TagCommand cmd = testRepo.git().tag()
.setName(name)
.setAnnotated(true)
.setMessage(name)
.setTagger(tagger);
return cmd.call();
}
public static void fetch(TestRepository<?> testRepo, String spec)
throws GitAPIException {
FetchCommand fetch = testRepo.git().fetch();
@@ -144,6 +157,11 @@ public class GitUtil {
fetch.call();
}
public static PushResult pushHead(TestRepository<?> testRepo, String ref)
throws GitAPIException {
return pushHead(testRepo, ref, false);
}
public static PushResult pushHead(TestRepository<?> testRepo, String ref,
boolean pushTags) throws GitAPIException {
return pushHead(testRepo, ref, pushTags, false);
@@ -182,6 +200,20 @@ public class GitUtil {
assertThat(rru.getMessage()).isEqualTo(expectedMessage);
}
public static PushResult pushTag(TestRepository<?> testRepo, String tag)
throws GitAPIException {
return pushTag(testRepo, tag, false);
}
private static PushResult pushTag(TestRepository<?> testRepo, String tag,
boolean force) throws GitAPIException {
PushCommand pushCmd = testRepo.git().push();
pushCmd.setForce(force);
pushCmd.setRefSpecs(new RefSpec("refs/tags/" + tag + ":refs/tags/" + tag));
Iterable<PushResult> r = pushCmd.call();
return Iterables.getOnlyElement(r);
}
public static Optional<String> getChangeId(TestRepository<?> tr, ObjectId id)
throws IOException {
RevCommit c = tr.getRevWalk().parseCommit(id);