diff options
author | Gunnar Wagenknecht <gunnar@wagenknecht.org> | 2018-12-05 20:39:07 +0100 |
---|---|---|
committer | Gunnar Wagenknecht <gunnar@wagenknecht.org> | 2019-01-16 10:05:09 +0100 |
commit | 2343c688b19d9bce4e75ada280be44043ad2dca2 (patch) | |
tree | 061a681b16149286495972906d340c9bea8e51d4 /org.eclipse.jgit.test | |
parent | 159968abc4fad1546ff7651450067b8cbce3bf2a (diff) | |
download | jgit-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.test')
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java | 99 | ||||
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java | 201 |
2 files changed, 300 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java index 3a13aa5a41..9128bb66c0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java @@ -53,6 +53,7 @@ import java.io.File; import java.util.Date; import java.util.List; import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jgit.api.errors.EmptyCommitException; import org.eclipse.jgit.api.errors.WrongRepositoryStateException; @@ -61,9 +62,11 @@ import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.dircache.DirCacheEntry; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.GpgSigner; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.RefUpdate; @@ -628,4 +631,100 @@ public class CommitCommandTest extends RepositoryTestCase { builder.add(stage2); builder.add(stage3); } + + @Test + public void callSignerWithProperSigningKey() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + + String[] signingKey = new String[1]; + AtomicInteger callCount = new AtomicInteger(); + GpgSigner.setDefault(new GpgSigner() { + @Override + public void sign(CommitBuilder commit, String gpgSigningKey) { + signingKey[0] = gpgSigningKey; + callCount.incrementAndGet(); + } + }); + + // first call should use config, which is expected to be null at + // this time + git.commit().setSign(Boolean.TRUE).setMessage("initial commit") + .call(); + assertNull(signingKey[0]); + assertEquals(1, callCount.get()); + + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + + // second commit applies config value + String expectedConfigSigningKey = "config-" + System.nanoTime(); + StoredConfig config = git.getRepository().getConfig(); + config.setString("user", null, "signingKey", + expectedConfigSigningKey); + config.save(); + + git.commit().setSign(Boolean.TRUE).setMessage("initial commit") + .call(); + assertEquals(expectedConfigSigningKey, signingKey[0]); + assertEquals(2, callCount.get()); + + writeTrashFile("file3", "file3"); + git.add().addFilepattern("file3").call(); + + // now use specific on api + String expectedSigningKey = "my-" + System.nanoTime(); + git.commit().setSign(Boolean.TRUE).setSigningKey(expectedSigningKey) + .setMessage("initial commit").call(); + assertEquals(expectedSigningKey, signingKey[0]); + assertEquals(3, callCount.get()); + } + } + + @Test + public void callSignerOnlyWhenSigning() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + + AtomicInteger callCount = new AtomicInteger(); + GpgSigner.setDefault(new GpgSigner() { + @Override + public void sign(CommitBuilder commit, String gpgSigningKey) { + callCount.incrementAndGet(); + } + }); + + // first call should use config, which is expected to be null at + // this time + git.commit().setMessage("initial commit").call(); + assertEquals(0, callCount.get()); + + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + + // now force signing + git.commit().setSign(Boolean.TRUE).setMessage("commit").call(); + assertEquals(1, callCount.get()); + + writeTrashFile("file3", "file3"); + git.add().addFilepattern("file3").call(); + + // now rely on config + StoredConfig config = git.getRepository().getConfig(); + config.setBoolean("commit", null, "gpgSign", true); + config.save(); + + git.commit().setMessage("commit").call(); + assertEquals(2, callCount.get()); + + writeTrashFile("file4", "file4"); + git.add().addFilepattern("file4").call(); + + // now force "no-sign" (even though config is true) + git.commit().setSign(Boolean.FALSE).setMessage("commit").call(); + assertEquals(2, callCount.get()); + } + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java new file mode 100644 index 0000000000..27ea505618 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/CommitBuilderTest.java @@ -0,0 +1,201 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.fail; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.MessageFormat; + +import org.eclipse.jgit.internal.JGitText; +import org.junit.Test; + +public class CommitBuilderTest { + + private void assertGpgSignatureStringOutcome(String signature, + String expectedOutcome) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CommitBuilder.writeGpgSignatureString(signature, out); + String formatted_signature = new String(out.toByteArray(), US_ASCII); + assertEquals(expectedOutcome, formatted_signature); + } + + @Test + public void writeGpgSignatureString_1() throws Exception { + // @formatter:off + String signature = "-----BEGIN PGP SIGNATURE-----\n" + + "Version: BCPG v1.60\n" + + "\n" + + "iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" + + "opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" + + "gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" + + "uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" + + "3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" + + "IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" + + "=b9OI\n" + + "-----END PGP SIGNATURE-----"; + String expectedOutcome = "-----BEGIN PGP SIGNATURE-----\n" + + " Version: BCPG v1.60\n" + + " \n" + + " iQEcBAABCAAGBQJb9cVhAAoJEKX+6Axg/6TZeFsH/0CY0WX/z7U8+7S5giFX4wH4\n" + + " opvBwqyt6OX8lgNwTwBGHFNt8LdmDCCmKoq/XwkNi3ARVjLhe3gBcKXNoavvPk2Z\n" + + " gIg5ChevGkU4afWCOMLVEYnkCBGw2+86XhrK1P7gTHEk1Rd+Yv1ZRDJBY+fFO7yz\n" + + " uSBuF5RpEY2sJiIvp27Gub/rY3B5NTR/feO/z+b9oiP/fMUhpRwG5KuWUsn9NPjw\n" + + " 3tvbgawYpU/2UnS+xnavMY4t2fjRYjsoxndPLb2MUX8X7vC7FgWLBlmI/rquLZVM\n" + + " IQEKkjnA+lhejjK1rv+ulq4kGZJFKGYWYYhRDwFg5PTkzhudhN2SGUq5Wxq1Eg4=\n" + + " =b9OI\n" + + " -----END PGP SIGNATURE-----"; + // @formatter:on + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void writeGpgSignatureString_failsForNonAscii() throws Exception { + String signature = "Ü Ä"; + try { + CommitBuilder.writeGpgSignatureString(signature, + new ByteArrayOutputStream()); + fail("Exception expected"); + } catch (IllegalArgumentException e) { + // good + String message = MessageFormat.format(JGitText.get().notASCIIString, + signature); + assertEquals(message, e.getMessage()); + } + } + + @Test + public void writeGpgSignatureString_oneLineNotModified() throws Exception { + String signature = " A string "; + String expectedOutcome = signature; + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void writeGpgSignatureString_preservesRandomWhitespace() + throws Exception { + // @formatter:off + String signature = " String with \n" + + "Line 2\n" + + " Line 3\n" + + "Line 4 \n" + + " Line 5 "; + String expectedOutcome = " String with \n" + + " Line 2\n" + + " Line 3\n" + + " Line 4 \n" + + " Line 5 "; + // @formatter:on + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void writeGpgSignatureString_replaceCR() throws Exception { + // @formatter:off + String signature = "String with \r" + + "Line 2\r" + + "Line 3\r" + + "Line 4\r" + + "Line 5"; + String expectedOutcome = "String with \n" + + " Line 2\n" + + " Line 3\n" + + " Line 4\n" + + " Line 5"; + // @formatter:on + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void writeGpgSignatureString_replaceCRLF() throws Exception { + // @formatter:off + String signature = "String with \r\n" + + "Line 2\r\n" + + "Line 3\r\n" + + "Line 4\r\n" + + "Line 5"; + String expectedOutcome = "String with \n" + + " Line 2\n" + + " Line 3\n" + + " Line 4\n" + + " Line 5"; + // @formatter:on + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void writeGpgSignatureString_replaceCRLFMixed() throws Exception { + // @formatter:off + String signature = "String with \r" + + "Line 2\r\n" + + "Line 3\r" + + "Line 4\r\n" + + "Line 5"; + String expectedOutcome = "String with \n" + + " Line 2\n" + + " Line 3\n" + + " Line 4\n" + + " Line 5"; + // @formatter:on + assertGpgSignatureStringOutcome(signature, expectedOutcome); + } + + @Test + public void setGpgSignature() throws Exception { + GpgSignature dummy = new GpgSignature(new byte[0]); + + CommitBuilder builder = new CommitBuilder(); + assertNull(builder.getGpgSignature()); + + builder.setGpgSignature(dummy); + assertSame(dummy, builder.getGpgSignature()); + + builder.setGpgSignature(null); + assertNull(builder.getGpgSignature()); + } +} |