summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorGunnar Wagenknecht <gunnar@wagenknecht.org>2018-12-05 20:39:07 +0100
committerGunnar Wagenknecht <gunnar@wagenknecht.org>2019-01-16 10:05:09 +0100
commit2343c688b19d9bce4e75ada280be44043ad2dca2 (patch)
tree061a681b16149286495972906d340c9bea8e51d4 /org.eclipse.jgit
parent159968abc4fad1546ff7651450067b8cbce3bf2a (diff)
downloadjgit-2343c688b19d9bce4e75ada280be44043ad2dca2.tar.gz
jgit-2343c688b19d9bce4e75ada280be44043ad2dca2.zip
Allow CommitCommand to sign commits
This change introduces the concept of a GpgSigner which will sign commits. The GpgSigner will be of a specific implementation (eg., Bouncycastle or OpenPgP executable). The actual implementation is not part of this change. Bug: 382212 Change-Id: Iea5da1e885c039e06bc8d679d46b124cbe504c8e Also-by: Medha Bhargav Prabhala <mprabhala@salesforce.com> Signed-off-by: Medha Bhargav Prabhala <mprabhala@salesforce.com> Signed-off-by: Gunnar Wagenknecht <gunnar@wagenknecht.org>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java72
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java69
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java95
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java98
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java100
7 files changed, 435 insertions, 1 deletions
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index fca9018db0..dc26e58689 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -505,6 +505,7 @@ oldIdMustNotBeNull=Expected old ID must not be null
onlyAlreadyUpToDateAndFastForwardMergesAreAvailable=only already-up-to-date and fast forward merges are available
onlyOneFetchSupported=Only one fetch supported
onlyOneOperationCallPerConnectionIsSupported=Only one operation call per connection is supported.
+onlyOpenPgpSupportedForSigning=OpenPGP is the only supported signing option with JGit at this time (gpg.format must be set to openpgp).
openFilesMustBeAtLeast1=Open files must be >= 1
openingConnection=Opening connection
operationCanceled=Operation {0} was canceled
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index d07532c092..00d3842dae 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -61,6 +61,7 @@ import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.UnmergedPathsException;
+import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuildIterator;
@@ -76,6 +77,9 @@ import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.GpgConfig;
+import org.eclipse.jgit.lib.GpgConfig.GpgFormat;
+import org.eclipse.jgit.lib.GpgSigner;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
@@ -139,6 +143,12 @@ public class CommitCommand extends GitCommand<RevCommit> {
private Boolean allowEmpty;
+ private Boolean signCommit;
+
+ private String signingKey;
+
+ private GpgSigner gpgSigner;
+
/**
* Constructor for CommitCommand
*
@@ -251,6 +261,11 @@ public class CommitCommand extends GitCommand<RevCommit> {
commit.setParentIds(parents);
commit.setTreeId(indexTreeId);
+
+ if (signCommit.booleanValue()) {
+ gpgSigner.sign(commit, signingKey);
+ }
+
ObjectId commitId = odi.insert(commit);
odi.flush();
@@ -517,9 +532,10 @@ public class CommitCommand extends GitCommand<RevCommit> {
*
* @throws NoMessageException
* if the commit message has not been specified
+ * @throws UnsupportedSigningFormatException if the configured gpg.format is not supported
*/
private void processOptions(RepositoryState state, RevWalk rw)
- throws NoMessageException {
+ throws NoMessageException, UnsupportedSigningFormatException {
if (committer == null)
committer = new PersonIdent(repo);
if (author == null && !amend)
@@ -572,6 +588,22 @@ public class CommitCommand extends GitCommand<RevCommit> {
// as long as we don't support -C option we have to have
// an explicit message
throw new NoMessageException(JGitText.get().commitMessageNotSpecified);
+
+ GpgConfig gpgConfig = new GpgConfig(repo.getConfig());
+ if (signCommit == null) {
+ signCommit = gpgConfig.isSignCommits() ? Boolean.TRUE
+ : Boolean.FALSE;
+ }
+ if (signingKey == null) {
+ signingKey = gpgConfig.getSigningKey();
+ }
+ if (gpgSigner == null) {
+ if (gpgConfig.getKeyFormat() != GpgFormat.OPENPGP) {
+ throw new UnsupportedSigningFormatException(
+ JGitText.get().onlyOpenPgpSupportedForSigning);
+ }
+ gpgSigner = GpgSigner.getDefault();
+ }
}
private boolean isMergeDuringRebase(RepositoryState state) {
@@ -873,4 +905,42 @@ public class CommitCommand extends GitCommand<RevCommit> {
hookOutRedirect.put(hookName, hookStdOut);
return this;
}
+
+ /**
+ * Sets the signing key
+ * <p>
+ * Per spec of user.signingKey: this will be sent to the GPG program as is,
+ * i.e. can be anything supported by the GPG program.
+ * </p>
+ * <p>
+ * Note, if none was set or <code>null</code> is specified a default will be
+ * obtained from the configuration.
+ * </p>
+ *
+ * @param signingKey
+ * signing key (maybe <code>null</code>)
+ * @return {@code this}
+ * @since 5.3
+ */
+ public CommitCommand setSigningKey(String signingKey) {
+ checkCallable();
+ this.signingKey = signingKey;
+ return this;
+ }
+
+ /**
+ * Sets whether the commit should be signed.
+ *
+ * @param sign
+ * <code>true</code> to sign, <code>false</code> to not sign and
+ * <code>null</code> for default behavior (read from
+ * configuration)
+ * @return {@code this}
+ * @since 5.3
+ */
+ public CommitCommand setSign(Boolean sign) {
+ checkCallable();
+ this.signCommit = sign;
+ return this;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
new file mode 100644
index 0000000000..eb5db6ad16
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/UnsupportedSigningFormatException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2018, Salesforce and
+ * other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v1.0 which accompanies this
+ * distribution, is reproduced below, and is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api.errors;
+
+/**
+ * Exception thrown when the configured gpg.format is not supported.
+ *
+ * @since 5.3
+ */
+public class UnsupportedSigningFormatException extends GitAPIException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor for UnsupportedGpgFormatException
+ *
+ * @param message
+ * error message
+ * @param cause
+ * a {@link java.lang.Throwable}
+ */
+ public UnsupportedSigningFormatException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Constructor for UnsupportedGpgFormatException
+ *
+ * @param message
+ * error message
+ */
+ public UnsupportedSigningFormatException(String message) {
+ super(message);
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index a24cff1e49..9da7f15746 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -566,6 +566,7 @@ public class JGitText extends TranslationBundle {
/***/ public String onlyAlreadyUpToDateAndFastForwardMergesAreAvailable;
/***/ public String onlyOneFetchSupported;
/***/ public String onlyOneOperationCallPerConnectionIsSupported;
+ /***/ public String onlyOpenPgpSupportedForSigning;
/***/ public String openFilesMustBeAtLeast1;
/***/ public String openingConnection;
/***/ public String operationCanceled;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
index c30833d0a6..a30f042531 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitBuilder.java
@@ -49,11 +49,15 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
+import java.text.MessageFormat;
import java.util.List;
+import org.eclipse.jgit.internal.JGitText;
+
/**
* Mutable builder to construct a commit recording the state of a project.
*
@@ -76,6 +80,8 @@ public class CommitBuilder {
private static final byte[] hcommitter = Constants.encodeASCII("committer"); //$NON-NLS-1$
+ private static final byte[] hgpgsig = Constants.encodeASCII("gpgsig"); //$NON-NLS-1$
+
private static final byte[] hencoding = Constants.encodeASCII("encoding"); //$NON-NLS-1$
private ObjectId treeId;
@@ -86,6 +92,8 @@ public class CommitBuilder {
private PersonIdent committer;
+ private GpgSignature gpgSignature;
+
private String message;
private Charset encoding;
@@ -156,6 +164,38 @@ public class CommitBuilder {
}
/**
+ * Set the GPG signature of this commit
+ * <p>
+ * Note, the signature set here will change the payload of the commit, i.e.
+ * the output of {@link #build()} will include the signature. Thus, the
+ * typical flow will be:
+ * <ol>
+ * <li>call {@link #build()} without a signature set to obtain payload</li>
+ * <li>create {@link GpgSignature} from payload</li>
+ * <li>set {@link GpgSignature}</li>
+ * </ol>
+ * </p>
+ *
+ * @param newSignature
+ * the signature to set or <code>null</code> to unset
+ * @since 5.3
+ */
+ public void setGpgSignature(GpgSignature newSignature) {
+ gpgSignature = newSignature;
+ }
+
+ /**
+ * Get the GPG signature of this commit.
+ *
+ * @return the GPG signature of this commit, maybe <code>null</code> if the
+ * commit is not to be signed
+ * @since 5.3
+ */
+ public GpgSignature getGpgSignature() {
+ return gpgSignature;
+ }
+
+ /**
* Get the ancestors of this commit.
*
* @return the ancestors of this commit. Never null.
@@ -316,6 +356,13 @@ public class CommitBuilder {
w.flush();
os.write('\n');
+ if (getGpgSignature() != null) {
+ os.write(hgpgsig);
+ os.write(' ');
+ writeGpgSignatureString(getGpgSignature().toExternalString(), os);
+ os.write('\n');
+ }
+
if (getEncoding() != UTF_8) {
os.write(hencoding);
os.write(' ');
@@ -339,6 +386,50 @@ public class CommitBuilder {
}
/**
+ * Writes signature to output as per <a href=
+ * "https://github.com/git/git/blob/master/Documentation/technical/signature-format.txt#L66,L89">gpgsig
+ * header</a>.
+ * <p>
+ * CRLF and CR will be sanitized to LF and signature will have a hanging
+ * indent of one space starting with line two.
+ * </p>
+ *
+ * @param in
+ * signature string with line breaks
+ * @param out
+ * output stream
+ * @throws IOException
+ * thrown by the output stream
+ * @throws IllegalArgumentException
+ * if the signature string contains non 7-bit ASCII chars
+ */
+ static void writeGpgSignatureString(String in, OutputStream out)
+ throws IOException, IllegalArgumentException {
+ for (int i = 0; i < in.length(); ++i) {
+ char ch = in.charAt(i);
+ if (ch == '\r') {
+ if (i + 1 < in.length() && in.charAt(i + 1) == '\n') {
+ out.write('\n');
+ out.write(' ');
+ ++i;
+ } else {
+ out.write('\n');
+ out.write(' ');
+ }
+ } else if (ch == '\n') {
+ out.write('\n');
+ out.write(' ');
+ } else {
+ // sanity check
+ if (ch > 127)
+ throw new IllegalArgumentException(MessageFormat
+ .format(JGitText.get().notASCIIString, in));
+ out.write(ch);
+ }
+ }
+ }
+
+ /**
* Format this builder's state as a commit object.
*
* @return this object in the canonical commit format, suitable for storage
@@ -377,6 +468,10 @@ public class CommitBuilder {
r.append(committer != null ? committer.toString() : "NOT_SET");
r.append("\n");
+ r.append("gpgSignature ");
+ r.append(gpgSignature != null ? gpgSignature.toString() : "NOT_SET");
+ r.append("\n");
+
if (encoding != null && encoding != UTF_8) {
r.append("encoding ");
r.append(encoding.name());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java
new file mode 100644
index 0000000000..663f850f0a
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSignature.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+import java.io.Serializable;
+
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * A structure for holding GPG signature together with additional related data.
+ *
+ * @since 5.3
+ */
+public class GpgSignature implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private byte[] signature;
+
+ /**
+ * Creates a new instance with the specified signature
+ *
+ * @param signature
+ * the signature
+ */
+ public GpgSignature(@NonNull byte[] signature) {
+ this.signature = signature;
+ }
+
+ /**
+ * Format for Git storage.
+ * <p>
+ * This returns the ASCII Armor as per
+ * https://tools.ietf.org/html/rfc4880#section-6.2.
+ * </p>
+ *
+ * @return a string of the signature ready to be embedded in a Git object
+ */
+ public String toExternalString() {
+ return new String(signature, US_ASCII);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @SuppressWarnings("nls")
+ public String toString() {
+ final StringBuilder r = new StringBuilder();
+
+ r.append("GpgSignature[");
+ r.append(
+ this.signature != null ? "length " + signature.length : "null");
+ r.append("]");
+
+ return r.toString();
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
new file mode 100644
index 0000000000..e509c9783f
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2018, Salesforce.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.lib;
+
+import org.eclipse.jgit.annotations.NonNull;
+
+/**
+ * Creates GPG signatures for Git objects.
+ *
+ * @since 5.3
+ */
+public abstract class GpgSigner {
+
+ private static GpgSigner defaultSigner;
+
+ /**
+ * Get the default signer, or <code>null</code>.
+ *
+ * @return the default signer, or <code>null</code>.
+ */
+ public static GpgSigner getDefault() {
+ return defaultSigner;
+ }
+
+ /**
+ * Set the default signer.
+ *
+ * @param signer
+ * the new default signer, may be <code>null</code> to select no
+ * default.
+ */
+ public static void setDefault(GpgSigner signer) {
+ GpgSigner.defaultSigner = signer;
+ }
+
+ /**
+ * Signs the specified commit.
+ *
+ * <p>
+ * Implementors should obtain the payload for signing from the specified
+ * commit via {@link CommitBuilder#build()} and create a proper
+ * {@link GpgSignature}. The generated signature must be set on the
+ * specified {@code commit} (see
+ * {@link CommitBuilder#setGpgSignature(GpgSignature)}).
+ * </p>
+ * <p>
+ * Any existing signature on the commit must be discarded prior obtaining
+ * the payload via {@link CommitBuilder#build()}.
+ * </p>
+ *
+ * @param commit
+ * the commit to sign (must not be <code>null</code> and must be
+ * complete to allow proper calculation of payload)
+ * @param gpgSigningKey
+ * the signing key (passed as is to the GPG signing tool)
+ */
+ public abstract void sign(@NonNull CommitBuilder commit,
+ String gpgSigningKey);
+
+}