Notedb: Store patch set push certificates in notes

Unlike other fields, push certificates have a predefined format that
includes newlines, so they are not particularly appropriate to store
in a single "Key: Value" footer. Moreover, we already reserve the body
of the meta commit message for ChangeMessages.

Sidestep any ambiguity by storing push certificates in the note for
the revision. Optionally parse a push certificate as the first thing
in the note file, before any inline comments.

Change-Id: Ia8c0674f3b40f6ec100cc9fac8ffec671833774b
This commit is contained in:
Dave Borowitz
2016-01-26 12:29:14 -05:00
parent 625a390b18
commit 3bbe39a26b
7 changed files with 200 additions and 34 deletions

View File

@@ -14,27 +14,63 @@
package com.google.gerrit.server.notedb;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Bytes;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchLineComment;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.RawParseUtils;
import java.io.IOException;
class RevisionNote {
static final int MAX_NOTE_SZ = 25 << 20;
private static final byte[] CERT_HEADER =
"certificate version ".getBytes(UTF_8);
// See org.eclipse.jgit.transport.PushCertificateParser.END_SIGNATURE
private static final byte[] END_SIGNATURE =
"-----END PGP SIGNATURE-----".getBytes(UTF_8);
private static void trimLeadingEmptyLines(byte[] bytes, MutableInteger p) {
while (p.value < bytes.length && bytes[p.value] == '\n') {
p.value++;
}
}
private static String parsePushCert(Change.Id changeId, byte[] bytes,
MutableInteger p) throws ConfigInvalidException {
if (RawParseUtils.match(bytes, p.value, CERT_HEADER) < 0) {
return null;
}
int end = Bytes.indexOf(bytes, END_SIGNATURE);
if (end < 0) {
throw ChangeNotes.parseException(
changeId, "invalid push certificate in note");
}
int start = p.value;
p.value = end + END_SIGNATURE.length;
return new String(bytes, start, p.value);
}
final ImmutableList<PatchLineComment> comments;
final String pushCert;
RevisionNote(Change.Id changeId, ObjectReader reader, ObjectId noteId)
throws ConfigInvalidException, IOException {
byte[] bytes = reader.open(noteId, OBJ_BLOB).getCachedBytes(MAX_NOTE_SZ);
MutableInteger p = new MutableInteger();
trimLeadingEmptyLines(bytes, p);
pushCert = parsePushCert(changeId, bytes, p);
trimLeadingEmptyLines(bytes, p);
comments = ImmutableList.copyOf(CommentsInNotesUtil.parseNote(
bytes, changeId, PatchLineComment.Status.PUBLISHED));
bytes, p, changeId, PatchLineComment.Status.PUBLISHED));
}
}