You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by el...@apache.org on 2021/03/17 14:49:08 UTC

[maven-gpg-plugin] branch master updated: [MGPG-79] fix handling of external pinentry programs in case the passphrase is not given (#9)

This is an automated email from the ASF dual-hosted git repository.

elharo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-gpg-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new e4dc062  [MGPG-79] fix handling of external pinentry programs in case the passphrase is not given (#9)
e4dc062 is described below

commit e4dc0625f45f611efc9f8c0b39dc8fd80cdb90dd
Author: Frederik Boster <fr...@boster.de>
AuthorDate: Wed Mar 17 15:47:11 2021 +0100

    [MGPG-79] fix handling of external pinentry programs in case the passphrase is not given (#9)
    
    * [MGPG-79] fix handling of external pinentry programs in case the passphrase is not given.
---
 pom.xml                                            |  49 ++++++++++
 .../invoker.properties                             |  18 ++++
 src/it/sign-release-without-passphrase/pom.xml     | 100 +++++++++++++++++++
 src/it/sign-release-without-passphrase/verify.bsh  |  38 ++++++++
 .../org/apache/maven/plugins/gpg/GpgSigner.java    |  36 +++++--
 .../apache/maven/plugins/gpg/it/BuildResult.java   |  48 ++++++++++
 .../plugins/gpg/it/GpgSignAttachedMojoIT.java      |  74 ++++++++++++++
 .../maven/plugins/gpg/it/InvokerTestUtils.java     | 106 +++++++++++++++++++++
 src/test/resources/gnupg/gpg-agent.conf            |   5 +
 src/test/resources/it/settings.xml                 |  59 ++++++++++++
 .../pom.xml                                        |  97 +++++++++++++++++++
 11 files changed, 622 insertions(+), 8 deletions(-)

diff --git a/pom.xml b/pom.xml
index abcc0fd..8869f6a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,6 +65,7 @@ under the License.
     <mavenVersion>3.0</mavenVersion>
     <javaVersion>7</javaVersion>
     <project.build.outputTimestamp>2020-04-12T12:45:04Z</project.build.outputTimestamp>
+    <resource.delimiter>@</resource.delimiter>
   </properties>
 
   <dependencies>
@@ -145,9 +146,33 @@ under the License.
       <version>2.2</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven.shared</groupId>
+      <artifactId>maven-invoker</artifactId>
+      <version>3.1.0</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
+    <testResources>
+      <testResource>
+        <directory>${basedir}/src/test/resources</directory>
+        <filtering>true</filtering>
+        <includes>
+          <include>**/pom.xml</include>
+          <include>**/settings.xml</include>
+        </includes>
+      </testResource>
+      <testResource>
+        <directory>${basedir}/src/test/resources</directory>
+        <excludes>
+          <exclude>**/pom.xml</exclude>
+          <exclude>**/settings.xml</exclude>
+        </excludes>
+      </testResource>
+    </testResources>
+
     <pluginManagement>
       <plugins>
         <plugin>
@@ -207,6 +232,30 @@ under the License.
         <plugins>
           <plugin>
             <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>integration-test</goal>
+                  <goal>verify</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <environmentVariables>
+                <JENKINS_MAVEN_AGENT_DISABLED>true</JENKINS_MAVEN_AGENT_DISABLED>
+              </environmentVariables>
+              <systemPropertyVariables>
+                <maven.home>${maven.home}</maven.home>
+                <https.protocols>${https.protocols}</https.protocols>
+                <gpg.homedir>${project.build.testOutputDirectory}/gnupg</gpg.homedir>
+                <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+                <settingsFile>/it/settings.xml</settingsFile>
+              </systemPropertyVariables>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-invoker-plugin</artifactId>
             <configuration>
               <settingsFile>src/it/settings.xml</settingsFile>
diff --git a/src/it/sign-release-without-passphrase/invoker.properties b/src/it/sign-release-without-passphrase/invoker.properties
new file mode 100644
index 0000000..f2a7dfb
--- /dev/null
+++ b/src/it/sign-release-without-passphrase/invoker.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+invoker.buildResult = failure
diff --git a/src/it/sign-release-without-passphrase/pom.xml b/src/it/sign-release-without-passphrase/pom.xml
new file mode 100644
index 0000000..8e279f5
--- /dev/null
+++ b/src/it/sign-release-without-passphrase/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.gpg.srwop</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0</version>
+  <packaging>jar</packaging>
+
+  <description>
+    Tests that signing with a missing passphrase in Maven batch mode (non-interactive mode) does not hang.
+  </description>
+
+  <properties>
+    <maven.test.skip>true</maven.test.skip>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-gpg-plugin</artifactId>
+        <version>@project.version@</version>
+        <configuration>
+          <passphraseServerId>non-existent</passphraseServerId>
+        </configuration>
+        <executions>
+          <execution>
+            <id>sign-artifacts</id>
+            <goals>
+              <goal>sign</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <updateReleaseInfo>true</updateReleaseInfo>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>2.1</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.0.4</version>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.3.1</version>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/src/it/sign-release-without-passphrase/verify.bsh b/src/it/sign-release-without-passphrase/verify.bsh
new file mode 100644
index 0000000..8ff268c
--- /dev/null
+++ b/src/it/sign-release-without-passphrase/verify.bsh
@@ -0,0 +1,38 @@
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import org.codehaus.plexus.util.FileUtils;
+
+File buildLog = new File( basedir, "build.log" );
+String logContent = FileUtils.fileRead(buildLog);
+
+// assert that the Maven build properly failed and did not time out
+if ( !logContent.contains( "Total time: " ) || !logContent.contains( "Finished at: " ) )
+{
+	throw new Exception( "Maven build did not fail, but timed out" );
+}
+
+// assert that the Maven build failed, because pinentry is not allowed in non-interactive mode
+if ( !logContent.contains( "[GNUPG:] FAILURE sign 67108949" ) )
+{
+	throw new Exception( "Maven build did not fail in consequence of pinentry not being available to GPG" );
+}
+
diff --git a/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java b/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java
index 65dd396..3fb0f3e 100644
--- a/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java
+++ b/src/main/java/org/apache/maven/plugins/gpg/GpgSigner.java
@@ -97,20 +97,25 @@ public class GpgSigner
                 cmd.createArg().setValue( "--no-use-agent" );
             }
         }
-        else
-        {
-            cmd.createArg().setValue( "--pinentry-mode" );
-            cmd.createArg().setValue( "loopback" );
-        }
 
         InputStream in = null;
         if ( null != passphrase )
         {
-            // make --passphrase-fd effective in gpg2
-            cmd.createArg().setValue( "--batch" );
+            if ( gpgVersion.isAtLeast( GpgVersion.parse( "2.0" ) ) )
+            {
+                // required for option --passphrase-fd since GPG 2.0
+                cmd.createArg().setValue( "--batch" );
+            }
 
-            cmd.createArg().setValue( "--passphrase-fd" );
+            if ( gpgVersion.isAtLeast( GpgVersion.parse( "2.1" ) ) )
+            {
+                // required for option --passphrase-fd since GPG 2.1
+                cmd.createArg().setValue( "--pinentry-mode" );
+                cmd.createArg().setValue( "loopback" );
+            }
 
+            // make --passphrase-fd effective in gpg2
+            cmd.createArg().setValue( "--passphrase-fd" );
             cmd.createArg().setValue( "0" );
 
             // Prepare the input stream which will be used to pass the passphrase to the executable
@@ -128,9 +133,24 @@ public class GpgSigner
 
         cmd.createArg().setValue( "--detach-sign" );
 
+        if ( getLog().isDebugEnabled() )
+        {
+            // instruct GPG to write status information to stdout
+            cmd.createArg().setValue( "--status-fd" );
+            cmd.createArg().setValue( "1" );
+        }
+
         if ( !isInteractive )
         {
+            cmd.createArg().setValue( "--batch" );
             cmd.createArg().setValue( "--no-tty" );
+
+            if ( null == passphrase && gpgVersion.isAtLeast( GpgVersion.parse( "2.1" ) ) )
+            {
+                // prevent GPG from spawning input prompts in Maven non-interactive mode
+                cmd.createArg().setValue( "--pinentry-mode" );
+                cmd.createArg().setValue( "error" );
+            }
         }
 
         if ( !defaultKeyring )
diff --git a/src/test/java/org/apache/maven/plugins/gpg/it/BuildResult.java b/src/test/java/org/apache/maven/plugins/gpg/it/BuildResult.java
new file mode 100644
index 0000000..3e40566
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/gpg/it/BuildResult.java
@@ -0,0 +1,48 @@
+package org.apache.maven.plugins.gpg.it;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.apache.maven.shared.invoker.InvocationResult;
+
+public class BuildResult
+{
+
+    private final File buildLog;
+    private final InvocationResult invocationResult;
+
+    public BuildResult( final File buildLog, final InvocationResult invocationResult )
+    {
+        this.buildLog = buildLog;
+        this.invocationResult = invocationResult;
+    }
+
+    public File getBuildLog()
+    {
+        return buildLog;
+    }
+
+    public InvocationResult getInvocationResult()
+    {
+        return invocationResult;
+    }
+
+}
diff --git a/src/test/java/org/apache/maven/plugins/gpg/it/GpgSignAttachedMojoIT.java b/src/test/java/org/apache/maven/plugins/gpg/it/GpgSignAttachedMojoIT.java
new file mode 100644
index 0000000..ea36ac1
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/gpg/it/GpgSignAttachedMojoIT.java
@@ -0,0 +1,74 @@
+package org.apache.maven.plugins.gpg.it;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+
+import java.io.File;
+
+import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.codehaus.plexus.util.FileUtils;
+import org.junit.Test;
+
+public class GpgSignAttachedMojoIT
+{
+
+    private final File mavenHome;
+    private final File localRepository;
+    private final File mavenUserSettings;
+    private final File gpgHome;
+
+    public GpgSignAttachedMojoIT() throws Exception
+    {
+        this.mavenHome = new File( System.getProperty( "maven.home" ) );
+        this.localRepository = new File( System.getProperty( "localRepositoryPath" ) );
+        this.mavenUserSettings = InvokerTestUtils.getTestResource( System.getProperty( "settingsFile" ) );
+        this.gpgHome = new File( System.getProperty( "gpg.homedir" ) );
+    }
+
+    @Test
+    public void testInteractiveWithoutPassphrase() throws Exception
+    {
+        // given
+        final File pomFile = InvokerTestUtils.getTestResource( "/it/sign-release-without-passphrase-interactive/pom.xml" );
+        final InvocationRequest request = InvokerTestUtils.createRequest( pomFile, mavenUserSettings, gpgHome );
+
+        // require Maven interactive mode
+        request.setBatchMode( false );
+
+        // when
+        final BuildResult result = InvokerTestUtils.executeRequest( request, mavenHome, localRepository );
+
+        final InvocationResult invocationResult = result.getInvocationResult();
+        final String buildLogContent = FileUtils.fileRead( result.getBuildLog() );
+
+        // then
+        assertThat( "Maven execution must fail", invocationResult.getExitCode(), not( 0 ) );
+        assertThat(
+            "Maven execution failed because no pinentry program is available",
+            buildLogContent,
+            containsString( "[GNUPG:] FAILURE sign 67108949" )
+        );
+    }
+
+}
diff --git a/src/test/java/org/apache/maven/plugins/gpg/it/InvokerTestUtils.java b/src/test/java/org/apache/maven/plugins/gpg/it/InvokerTestUtils.java
new file mode 100644
index 0000000..3dd041d
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/gpg/it/InvokerTestUtils.java
@@ -0,0 +1,106 @@
+package org.apache.maven.plugins.gpg.it;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Properties;
+
+import org.apache.commons.io.input.NullInputStream;
+import org.apache.maven.shared.invoker.DefaultInvocationRequest;
+import org.apache.maven.shared.invoker.DefaultInvoker;
+import org.apache.maven.shared.invoker.InvocationOutputHandler;
+import org.apache.maven.shared.invoker.InvocationRequest;
+import org.apache.maven.shared.invoker.InvocationResult;
+import org.apache.maven.shared.invoker.Invoker;
+import org.apache.maven.shared.invoker.InvokerLogger;
+import org.apache.maven.shared.invoker.MavenInvocationException;
+import org.apache.maven.shared.invoker.PrintStreamHandler;
+import org.apache.maven.shared.invoker.PrintStreamLogger;
+
+public class InvokerTestUtils
+{
+
+    public static InvocationRequest createRequest( final File pomFile, final File mavenUserSettings, final File gpgHome )
+    {
+        final InvocationRequest request = new DefaultInvocationRequest();
+        request.setUserSettingsFile( mavenUserSettings );
+        request.setShowVersion( true );
+        request.setDebug( true );
+        request.setShowErrors( true );
+        request.setTimeoutInSeconds( 60 ); // safeguard against GPG freezes
+        request.setGoals( Arrays.asList( "clean", "install" ) );
+        request.setPomFile( pomFile );
+
+        final Properties properties = new Properties();
+        request.setProperties( properties );
+
+        // Required for JRE 7 to connect to Maven Central with TLSv1.2
+        final String httpsProtocols = System.getProperty( "https.protocols" );
+        if ( httpsProtocols != null && !httpsProtocols.isEmpty() ) {
+            properties.setProperty( "https.protocols", httpsProtocols );
+        }
+
+        properties.setProperty( "gpg.homedir", gpgHome.getAbsolutePath() );
+
+        return request;
+    }
+
+    public static BuildResult executeRequest( final InvocationRequest request, final File mavenHome, final File localRepository )
+        throws FileNotFoundException, MavenInvocationException
+    {
+        final InvocationResult result;
+
+        final File buildLog = new File( request.getBaseDirectory( request.getPomFile().getParentFile() ), "build.log" );
+        try ( final PrintStream buildLogStream = new PrintStream( buildLog ) )
+        {
+            final InvocationOutputHandler buildLogOutputHandler = new PrintStreamHandler( buildLogStream, false );
+            final InvokerLogger logger = new PrintStreamLogger( buildLogStream, InvokerLogger.DEBUG );
+
+            final Invoker invoker = new DefaultInvoker();
+            invoker.setMavenHome( mavenHome );
+            invoker.setLocalRepositoryDirectory( localRepository );
+            invoker.setInputStream( new NullInputStream( 0 ) );
+            invoker.setOutputHandler( buildLogOutputHandler );
+            invoker.setErrorHandler( buildLogOutputHandler );
+            invoker.setLogger( logger );
+
+            result = invoker.execute( request );
+        }
+
+        return new BuildResult( buildLog, result );
+    }
+
+    public static File getTestResource( final String path ) throws URISyntaxException, FileNotFoundException
+    {
+        final URL resourceUrl = InvokerTestUtils.class.getResource( path );
+        if ( resourceUrl == null )
+        {
+            throw new FileNotFoundException( "Cannot find file " + path );
+        }
+
+        return new File( resourceUrl.toURI() );
+    }
+
+}
diff --git a/src/test/resources/gnupg/gpg-agent.conf b/src/test/resources/gnupg/gpg-agent.conf
new file mode 100644
index 0000000..00efc6f
--- /dev/null
+++ b/src/test/resources/gnupg/gpg-agent.conf
@@ -0,0 +1,5 @@
+# Prevent gpg-agent from caching the passphrase / unlocked key between integration tests
+ignore-cache-for-signing
+
+# Prevent pinentry input prompts from blocking integration tests
+pinentry-program pinentry-non-existent
diff --git a/src/test/resources/it/settings.xml b/src/test/resources/it/settings.xml
new file mode 100644
index 0000000..bc80ff2
--- /dev/null
+++ b/src/test/resources/it/settings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+
+    <profiles>
+        <profile>
+            <id>it-repo</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <repositories>
+                <repository>
+                    <id>local.central</id>
+                    <url>file://@settings.localRepository@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </repository>
+            </repositories>
+            <pluginRepositories>
+                <pluginRepository>
+                    <id>local.central</id>
+                    <url>file://@settings.localRepository@</url>
+                    <releases>
+                        <enabled>true</enabled>
+                    </releases>
+                    <snapshots>
+                        <enabled>true</enabled>
+                    </snapshots>
+                </pluginRepository>
+            </pluginRepositories>
+        </profile>
+    </profiles>
+
+</settings>
diff --git a/src/test/resources/it/sign-release-without-passphrase-interactive/pom.xml b/src/test/resources/it/sign-release-without-passphrase-interactive/pom.xml
new file mode 100644
index 0000000..64de500
--- /dev/null
+++ b/src/test/resources/it/sign-release-without-passphrase-interactive/pom.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.gpg.srwopi</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0</version>
+  <packaging>jar</packaging>
+
+  <description>
+    Tests that signing with a missing passphrase in Maven interactive mode does not hang.
+  </description>
+
+  <properties>
+    <maven.test.skip>true</maven.test.skip>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-gpg-plugin</artifactId>
+        <version>@project.version@</version>
+        <executions>
+          <execution>
+            <id>sign-artifacts</id>
+            <goals>
+              <goal>sign</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <updateReleaseInfo>true</updateReleaseInfo>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>2.1</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <version>2.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <version>2.0.4</version>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.3.1</version>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>