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>