You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by rf...@apache.org on 2019/04/06 16:29:58 UTC

[maven-gpg-plugin] 01/01: [MGPG-59] GPG Plugin: "gpg: signing failed: Inappropriate ioctl for device"

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

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

commit 4e21583f1241dccc3fa3d0b849d2ad3600d62cc2
Author: rfscholte <rf...@apache.org>
AuthorDate: Sat Apr 6 18:29:46 2019 +0200

    [MGPG-59] GPG Plugin: "gpg: signing failed: Inappropriate ioctl for device"
---
 Jenkinsfile                                        |   2 +-
 pom.xml                                            |  47 ++++---
 .../org/apache/maven/plugin/gpg/GpgSigner.java     |  30 ++++-
 .../org/apache/maven/plugin/gpg/GpgVersion.java    | 140 +++++++++++++++++++++
 .../apache/maven/plugin/gpg/GpgVersionParser.java  | 109 ++++++++++++++++
 .../apache/maven/plugin/gpg/GpgVersionTest.java    |  19 ++-
 6 files changed, 321 insertions(+), 26 deletions(-)

diff --git a/Jenkinsfile b/Jenkinsfile
index e9f05f7..059dc22 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-asfMavenTlpPlgnBuild()
+asfMavenTlpPlgnBuild([tmpWs:true])
diff --git a/pom.xml b/pom.xml
index b5dfceb..2afc642 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,6 +106,13 @@ under the License.
       <artifactId>plexus-sec-dispatcher</artifactId>
       <version>1.4</version>
     </dependency>
+    
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -129,24 +136,28 @@ under the License.
     <profile>
       <id>run-its</id>
       <build>
-        <pluginManagement>
-          <plugins>
-            <plugin>
-              <groupId>org.apache.maven.plugins</groupId>
-              <artifactId>maven-invoker-plugin</artifactId>
-              <configuration>
-                <settingsFile>src/it/settings.xml</settingsFile>
-                <goals>
-                  <goal>clean</goal>
-                  <goal>install</goal>
-                </goals>
-                <properties>
-                  <gpg.homedir>${project.build.testOutputDirectory}/gnupg</gpg.homedir>
-                </properties>
-              </configuration>
-            </plugin>
-          </plugins>
-        </pluginManagement>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-invoker-plugin</artifactId>
+            <configuration>
+              <settingsFile>src/it/settings.xml</settingsFile>
+              <pomIncludes>
+                <pomInclude>*</pomInclude>
+              </pomIncludes>
+              <pomExcludes>
+                <pomExclude>alternative-secret-keyring</pomExclude> <!-- not supported with gpg 2.1+ -->
+              </pomExcludes>
+              <goals>
+                <goal>clean</goal>
+                <goal>install</goal>
+              </goals>
+              <properties>
+                <gpg.homedir>${project.build.testOutputDirectory}/gnupg</gpg.homedir>
+              </properties>
+            </configuration>
+          </plugin>
+        </plugins>
       </build>
     </profile>
   </profiles>
diff --git a/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java b/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java
index 39d5d83..641706e 100644
--- a/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java
+++ b/src/main/java/org/apache/maven/plugin/gpg/GpgSigner.java
@@ -65,6 +65,10 @@ public class GpgSigner
         {
             cmd.setExecutable( "gpg" + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" ) );
         }
+        
+        GpgVersionParser versionParser = GpgVersionParser.parse( executable );
+        
+        GpgVersion gpgVersion = versionParser.getGpgVersion();
 
         if ( args != null )
         {
@@ -80,13 +84,21 @@ public class GpgSigner
             cmd.createArg().setFile( homeDir );
         }
 
-        if ( useAgent )
+        if ( gpgVersion.isBefore( GpgVersion.parse( "2.1" ) ) )
         {
-            cmd.createArg().setValue( "--use-agent" );
+            if ( useAgent )
+            {
+                cmd.createArg().setValue( "--use-agent" );
+            }
+            else
+            {
+                cmd.createArg().setValue( "--no-use-agent" );
+            }
         }
         else
         {
-            cmd.createArg().setValue( "--no-use-agent" );
+            cmd.createArg().setValue( "--pinentry-mode" );
+            cmd.createArg().setValue( "loopback" );
         }
 
         InputStream in = null;
@@ -126,8 +138,16 @@ public class GpgSigner
 
         if ( StringUtils.isNotEmpty( secretKeyring ) )
         {
-            cmd.createArg().setValue( "--secret-keyring" );
-            cmd.createArg().setValue( secretKeyring );
+            if ( gpgVersion.isBefore( GpgVersion.parse( "2.1" ) ) ) 
+            {
+                cmd.createArg().setValue( "--secret-keyring" );
+                cmd.createArg().setValue( secretKeyring );
+            }
+            else
+            {
+                getLog().warn( "'secretKeyring' is an obsolete option and ignored. All secret keys "
+                    + "are stored in the ‘private-keys-v1.d’ directory below the GnuPG home directory." );
+            }
         }
 
         if ( StringUtils.isNotEmpty( publicKeyring ) )
diff --git a/src/main/java/org/apache/maven/plugin/gpg/GpgVersion.java b/src/main/java/org/apache/maven/plugin/gpg/GpgVersion.java
new file mode 100644
index 0000000..49010ab
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/gpg/GpgVersion.java
@@ -0,0 +1,140 @@
+package org.apache.maven.plugin.gpg;
+
+/*
+ * 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.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 
+ * @author Robert Scholte
+ * @since 3.0.0
+ */
+public class GpgVersion implements Comparable<GpgVersion>
+{
+    private final String rawVersion;
+    
+    private GpgVersion( String rawVersion )
+    {
+        this.rawVersion = rawVersion;
+    }
+    
+    public static GpgVersion parse( String rawVersion )
+    {
+        return new GpgVersion( rawVersion );
+    }
+
+    @Override
+    public int compareTo( GpgVersion other )
+    {
+        Pattern p = Pattern.compile( "([.\\d]+)$" );
+        
+        String[] thisSegments;
+        Matcher m = p.matcher( rawVersion );
+        if ( m.find() )
+        {
+            thisSegments  = m.group( 1 ).split( "\\." );
+        }
+        else 
+        {
+          throw new IllegalArgumentException( "Can't parse version of " + this.rawVersion );   
+        }
+        
+        String[] otherSegments;
+        m = p.matcher( other.rawVersion );
+        if ( m.find() )
+        {
+            otherSegments  = m.group( 1 ).split( "\\." );
+        }
+        else 
+        {
+          throw new IllegalArgumentException( "Can't parse version of " + other.rawVersion );   
+        }
+        
+        int minSegments = Math.min( thisSegments.length, otherSegments.length );
+        
+        for ( int index = 0; index < minSegments; index++ )
+        {
+            int thisValue = Integer.parseInt( thisSegments[index] );
+            
+            int otherValue = Integer.parseInt( otherSegments[index] );
+            
+            int compareValue = Integer.compare( thisValue, otherValue );
+            
+            if ( compareValue != 0 )
+            {
+                return compareValue;
+            }
+        }
+        
+        return ( thisSegments.length - otherSegments.length );
+    }
+
+    /**
+     * Verify if this version is before some other version
+     * 
+     * @param other the version to compare with
+     * @return {@code true} is this is less than {@code other}, otherwise {@code false}
+     */
+    public boolean isBefore( GpgVersion other )
+    {
+        return this.compareTo( other ) < 0;
+    }
+
+    /**
+     * Verify if this version is before some other version
+     * 
+     * @param other the version to compare with
+     * @return {@code true}  is this is less than {@code other}, otherwise {@code false}
+     */
+    public boolean isBefore( String other )
+    {
+        return this.compareTo( parse( other ) ) < 0;
+    }
+
+    /**
+     * Verify if this version is at least some other version
+     * 
+     * @param other the version to compare with
+     * @return  {@code true}  is this is greater than or equal to {@code other}, otherwise {@code false}
+     */
+    public boolean isAtLeast( GpgVersion other )
+    {
+        return this.compareTo( other ) >= 0;
+    }
+
+    /**
+     * Verify if this version is at least some other version
+     * 
+     * @param other the version to compare with
+     * @return  {@code true} is this is greater than or equal to {@code other}, otherwise {@code false}
+     */
+    public boolean isAtLeast( String other )
+    {
+        return this.compareTo( parse( other ) ) >= 0;
+    }
+    
+    @Override
+    public String toString()
+    {
+        return rawVersion;
+    }
+    
+}
diff --git a/src/main/java/org/apache/maven/plugin/gpg/GpgVersionParser.java b/src/main/java/org/apache/maven/plugin/gpg/GpgVersionParser.java
new file mode 100644
index 0000000..7ec7b69
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugin/gpg/GpgVersionParser.java
@@ -0,0 +1,109 @@
+package org.apache.maven.plugin.gpg;
+
+/*
+ * 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.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.codehaus.plexus.util.Os;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.cli.CommandLineException;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+import org.codehaus.plexus.util.cli.StreamConsumer;
+
+/**
+ * 
+ * @author Robert Scholte
+ * @since 3.0.0
+ */
+public class GpgVersionParser
+{
+    private final GpgVersionConsumer consumer;
+    
+    private GpgVersionParser( GpgVersionConsumer consumer )
+    {
+        this.consumer = consumer;
+        
+    }
+    
+    public static GpgVersionParser parse( String executable )
+    {
+        Commandline cmd = new Commandline();
+
+        if ( StringUtils.isNotEmpty( executable ) )
+        {
+            cmd.setExecutable( executable );
+        }
+        else
+        {
+            cmd.setExecutable( "gpg" + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" ) );
+        }
+
+        
+        cmd.createArg().setValue( "--version" );
+        
+        GpgVersionConsumer out = new GpgVersionConsumer();
+        
+        try
+        {
+           CommandLineUtils.executeCommandLine( cmd, null, out, null );
+        }
+        catch ( CommandLineException e )
+        {
+            // TODO probably a dedicated exception
+        }
+        
+        return new GpgVersionParser( out );
+    }
+    
+    public GpgVersion getGpgVersion()
+    {
+        return consumer.gpgVersion;
+
+    }
+
+    /**
+     * Consumes the output of {@code gpg --version}
+     * 
+     * @author Robert Scholte
+     * @since 3.0.0
+     */
+    static class GpgVersionConsumer
+        implements StreamConsumer
+    {
+        private final Pattern gpgVersionPattern = Pattern.compile( "gpg \\(GnuPG\\) .+" );
+
+        private GpgVersion gpgVersion;
+        
+        @Override
+        public void consumeLine( String line )
+            throws IOException
+        {
+            Matcher m = gpgVersionPattern.matcher( line );
+            if ( m.matches() )
+            {
+                gpgVersion = GpgVersion.parse( m.group() );
+            }
+        }
+    }
+
+}
diff --git a/Jenkinsfile b/src/test/java/org/apache/maven/plugin/gpg/GpgVersionTest.java
similarity index 66%
copy from Jenkinsfile
copy to src/test/java/org/apache/maven/plugin/gpg/GpgVersionTest.java
index e9f05f7..2204aca 100644
--- a/Jenkinsfile
+++ b/src/test/java/org/apache/maven/plugin/gpg/GpgVersionTest.java
@@ -1,4 +1,6 @@
-/**
+package org.apache.maven.plugin.gpg;
+
+/*
  * 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
@@ -17,4 +19,17 @@
  * under the License.
  */
 
-asfMavenTlpPlgnBuild()
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class GpgVersionTest
+{
+    @Test
+    public void test()
+    {
+        assertTrue( GpgVersion.parse( "gpg (GnuPG) 2.2.1" ).isAtLeast( GpgVersion.parse( "gpg (GnuPG) 2.2.1" ) ) );
+        assertTrue( GpgVersion.parse( "gpg (GnuPG) 2.2.1" ).isAtLeast( GpgVersion.parse( "2.1" ) ) );
+    }
+
+}