[java-mvn-enforcer] branch main updated: JMVN-7 Make the enforcer understand zip/tgz files

Rod Widdowson rdw at steadingsoftware.com
Mon Dec 6 15:22:58 UTC 2021


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch main
in repository java-mvn-enforcer.

View the commit online:
http://git.shibboleth.net/view/?p=java-mvn-enforcer.git;a=commit;h=f407810caf081811286744c42e53191c5c25ca18

The following commit(s) were added to refs/heads/main by this push:
     new f407810  JMVN-7 Make the enforcer understand zip/tgz files
f407810 is described below

commit f407810caf081811286744c42e53191c5c25ca18
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Mon Dec 6 15:14:34 2021 +0000

    JMVN-7 Make the enforcer understand zip/tgz files
    
    https://shibboleth.atlassian.net/browse/JMVN-7
    
    This comes at the cost of no longer understansing directory trees
    but I can live with that
---
 pom.xml                                            |  5 ++
 .../mvn/enforcer/impl/BaseSigChecker.java          |  6 +-
 .../mvn/enforcer/impl/DependencyChecker.java       | 41 ++++++----
 .../shibboleth/mvn/enforcer/impl/JarEnforcer.java  | 87 ++++++++++++++++------
 .../shibboleth/mvn/enforcer/impl/M2SigChecker.java |  4 +-
 .../shibboleth/mvn/enforcer/impl/SigChecker.java   | 52 +++++++------
 6 files changed, 129 insertions(+), 66 deletions(-)

diff --git a/pom.xml b/pom.xml
index bf97bc8..baf8cb7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,11 @@
             <artifactId>spring-context</artifactId>
         </dependency>
 
+        <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-compress</artifactId>
+        </dependency>
+
         <!--  Provided because we are inside maven  -->
          <dependency>
             <groupId>org.apache.maven.plugins</groupId>
diff --git a/src/main/java/net/shibboleth/mvn/enforcer/impl/BaseSigChecker.java b/src/main/java/net/shibboleth/mvn/enforcer/impl/BaseSigChecker.java
index 4b3682b..946e7ae 100644
--- a/src/main/java/net/shibboleth/mvn/enforcer/impl/BaseSigChecker.java
+++ b/src/main/java/net/shibboleth/mvn/enforcer/impl/BaseSigChecker.java
@@ -94,7 +94,7 @@ public class BaseSigChecker {
      * @param artifact the {@link PomArtifact} for the jar file.
      * @return true if the signature passed (or some other "usual conditions)
      */
-    protected boolean checkSignature(final Path jarFile, final PomArtifact artifact) {
+    protected boolean checkSignature(final InputStream jarFile, final PomArtifact artifact) {
         final String group = artifact.getGroupId();
         final String id = artifact.getArtifactId();
         final String version = artifact.getVersion();
@@ -128,8 +128,8 @@ public class BaseSigChecker {
             return false;
         }
 
-        try (final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(jarFile.toFile()))) {
-            if (!keyRing.checkSignature(stream, sig)) {
+        try {
+            if (!keyRing.checkSignature(jarFile, sig)) {
                 report.format("%-30s: %-14s Signature Mismatch : %s in keyring %s\n",
                         id, version, keyRing.getKeyInfo(sig), group);
                 log.error("{} {} Signature Mismatch : ({}) in keyring for {}",
diff --git a/src/main/java/net/shibboleth/mvn/enforcer/impl/DependencyChecker.java b/src/main/java/net/shibboleth/mvn/enforcer/impl/DependencyChecker.java
index 1ad0854..962908a 100644
--- a/src/main/java/net/shibboleth/mvn/enforcer/impl/DependencyChecker.java
+++ b/src/main/java/net/shibboleth/mvn/enforcer/impl/DependencyChecker.java
@@ -38,6 +38,8 @@ import java.util.Set;
 
 import javax.annotation.Nonnull;
 
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
 import org.apache.maven.shared.invoker.DefaultInvoker;
 import org.apache.maven.shared.invoker.InvocationRequest;
@@ -105,15 +107,14 @@ public class DependencyChecker {
     }
     
     /** The Body of the Dependency test.  Are all the files what we expected? Who produced what?
-     * @param roots where to start looking
+     * @param archive what to look at
      * @param doAnalysis do we want to do the "and where did everything come from" analysis.
      * @return true if OK, false otherwise
      */
-    //Checkstyle: CyclomaticComplexity OFF
-    public boolean checkDependencies(final List<Path> roots, final boolean doAnalysis) {
+    public boolean checkDependencies(final ArchiveInputStream archive, final boolean doAnalysis) {
         final ParsedPom parentPom = projectContext.getParentPom();
         final int dupEntries = reportDupEntries();
-        if (!enumerateJars(roots)) {
+        if (!enumerateJars(archive)) {
             return true;
         }
 
@@ -295,21 +296,29 @@ public class DependencyChecker {
     }
 
     /** Get the jars and accumulate them into {@link #nameToVersion}.
-     * @param roots where to start looking
+     * @param archive what to look in
      * @return true if OK, false otherwise
      */
-    private boolean enumerateJars(final List<Path> roots) {
-        for (final Path root:roots) {
-            if (Files.notExists(root)) {
-                log.error("{} did not exist", root);
-                return false;
-            }
-            try {
-                Files.list(root).forEach(e -> addName(root.relativize(e).toString()));
-            } catch (final IOException e) {
-                log.error("Could not traverse tree from {}: ", root, e);
-                return false;
+    private boolean enumerateJars(final ArchiveInputStream archive) {
+        ArchiveEntry entry = null;
+        try {
+            while ((entry = archive.getNextEntry()) != null) {
+                if (!archive.canReadEntryData(entry)) {
+                    log.warn("Could not read next entry from {}", archive);
+                    continue;
+                }
+                if (entry.isDirectory()) {
+                    continue;
+                }
+                else if (!entry.getName().endsWith(".jar")) {
+                    continue;
+                }
+                final Path nameAsPath = Path.of(entry.getName());
+                addName(nameAsPath.getFileName().toString());
             }
+        } catch (final IOException e) {
+            log.error("Could not traverse archive");
+            return false;
         }
         return true;
     }
diff --git a/src/main/java/net/shibboleth/mvn/enforcer/impl/JarEnforcer.java b/src/main/java/net/shibboleth/mvn/enforcer/impl/JarEnforcer.java
index 2b62462..8f5de57 100644
--- a/src/main/java/net/shibboleth/mvn/enforcer/impl/JarEnforcer.java
+++ b/src/main/java/net/shibboleth/mvn/enforcer/impl/JarEnforcer.java
@@ -22,6 +22,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.net.URL;
@@ -34,6 +35,9 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
+import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
@@ -63,9 +67,10 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
     
     /** Relative path of the parent pom.*/
     private String parentPomDir=".";
-    /** Space separated list of locations to look for jars in. */
-    private String jarDirs="";
-    /** Where to get external data. Group */
+    /** Space separated list of tgz files. */
+    private String tgzFiles="";
+    /** Space separated list of tgz files. */
+    private String zipFiles="";    /** Where to get external data. Group */
     private String dataGroupId = "";
     /** Where to get external data. ArtifactName*/
     private String dataArtifactId = "";
@@ -111,17 +116,26 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
         EnforcerLogger.setMavenLogger(helper.getLog());
         log = EnforcerLogger.getLogger(JarEnforcer.class);
 
-        final List<Path> jarPaths = new ArrayList<>();
-        for (final String name: StringSupport.stringToList(jarDirs, XMLConstants.LIST_DELIMITERS)) {
+        final List<Path> tgzPaths = new ArrayList<>();
+        for (final String name: StringSupport.stringToList(tgzFiles, XMLConstants.LIST_DELIMITERS)) {
             final Path result = Path.of(name);
-            if (Files.notExists(result) || !Files.isDirectory(result)) {
-                log.warn("Directory {{} does not exist or is not a directory", name);
+            if (Files.notExists(result)) {
+                log.warn("Input file {} does not exist", name);
             } else {
-                jarPaths.add(result);
+                tgzPaths.add(result);
             }
         }
-        if (jarPaths.isEmpty()) {
-            throw new EnforcerRuleException("No <jarsDirs/> provided");
+        final List<Path> zipPaths = new ArrayList<>();
+        for (final String name: StringSupport.stringToList(zipFiles, XMLConstants.LIST_DELIMITERS)) {
+            final Path result = Path.of(name);
+            if (Files.notExists(result)) {
+                log.warn("Input file {} does not exist", name);
+            } else {
+                zipPaths.add(result);
+            }
+        }
+        if (zipPaths.isEmpty() && tgzPaths.isEmpty()) {
+            throw new EnforcerRuleException("No <tgzFiles/> or <zipFiles/> provided");
         }
         try {
             repositorySystem = helper.getComponent(org.apache.maven.repository.RepositorySystem.class);
@@ -158,8 +172,8 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
                 pomContext.initialize(pom);
 
                 final boolean m2Result = performM2Check(pomContext, target);
-                final boolean depdendencyResult = performDependencyCheck(pomContext, target, jarPaths);
-                final boolean signatureResult = performSignatureCheck(pomContext, target, jarPaths);
+                final boolean depdendencyResult = performDependencyCheck(pomContext, target, tgzPaths, zipPaths);
+                final boolean signatureResult = performSignatureCheck(pomContext, target, tgzPaths, zipPaths);
                 if (!depdendencyResult) {
                     throw new EnforcerRuleException(
                         "Dependency check failed, check the file ./target/dependencyReport.txt");
@@ -262,12 +276,14 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
     /** Do the signature check
      * @param pomContext Context for the work
      * @param target Target Directory of this project
-     * @param jarPaths the jars to look at.
+     * @param tgzPaths the tgzFiles to look at.
+     * @param zipPaths the zipFiles to look at.
      * @return if this worked (or was suppressed)
-     * @throws FileNotFoundException if a file was not found
-     * @throws EnforcerRuleException if we were doing an invaluid SNAPSHOT/nonSNAPSHOT test
+     * @throws IOException if a file was not found or archive handling failed
+     * @throws EnforcerRuleException if we were doing an invalid SNAPSHOT/nonSNAPSHOT test
      */
-    private boolean performSignatureCheck(final ProjectPomContext pomContext, final Path target, final List<Path> jarPaths) throws FileNotFoundException, EnforcerRuleException {
+    private boolean performSignatureCheck(final ProjectPomContext pomContext, final Path target,
+                                          final List<Path> tgzPaths, final List<Path> zipPaths) throws IOException, EnforcerRuleException {
         boolean signatureResult = true;
         if (checkSignatures) {
             if (isGPGDataASnapshot() && !pomContext.isSnapShot()) {
@@ -276,9 +292,22 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
             final File out = target.resolve("signatureReport.txt").toFile();
             try (final PrintWriter report =
                     new PrintWriter(new BufferedOutputStream(new FileOutputStream(out)))) {
+
                 report.format("Signature Testing started at %s\n\n", Instant.now().toString());
                 final SigChecker sigChecker = new SigChecker(pomContext, report);
-                signatureResult = sigChecker.testSignatures(jarPaths);
+
+                for (final Path tgzPath: tgzPaths) {
+                    report.format("Scanning %s \n\n", tgzPath);
+                    try (final InputStream inStream = new BufferedInputStream(new FileInputStream(tgzPath.toFile()))) {
+                        signatureResult &= sigChecker.testSignatures(new TarArchiveInputStream(new GzipCompressorInputStream(inStream)));
+                    }
+                }
+                for (final Path zipPath: zipPaths) {
+                    report.format("Scanning %s \n\n", zipPath);
+                    try (final InputStream inStream = new BufferedInputStream(new FileInputStream(zipPath.toFile()))) {
+                        signatureResult &= sigChecker.testSignatures(new ZipArchiveInputStream(inStream));
+                    }
+                }
                 report.format("Completed at %s\n\n", Instant.now().toString());
                 if (!signatureResult) {
                     log.error("Signature check failed, check the file ./target/signatureReport.txt");
@@ -291,11 +320,13 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
     /** Do the dependency check
      * @param pomContext Context for the work
      * @param target Target Directory of this project
-     * @param jarPaths the jars to look at.
+     * @param tgzPaths the tgzFiles to look at.
+     * @param zipPaths the zipFiles to look at.
      * @return if this worked (or was suppressed)
-     * @throws FileNotFoundException if a file was not found
+     * @throws IOException if a file was not found or archive handling failed
      */
-    private boolean performDependencyCheck(final ProjectPomContext pomContext, final Path target, final List<Path> jarPaths) throws FileNotFoundException {
+    private boolean performDependencyCheck(final ProjectPomContext pomContext, final Path target,
+                                           final List<Path> tgzPaths, final List<Path> zipPaths) throws IOException {
         boolean depdendencyResult = true;
         if (checkDependencies) {
             final File out = target.resolve("dependencyReport.txt").toFile();
@@ -303,8 +334,20 @@ public class JarEnforcer implements EnforcerRule, MavenLoader{
                     new BufferedOutputStream(new FileOutputStream(out)))) {
                 report.format("POM based Dependency Testing started at %s\n\n", Instant.now().toString());
 
-                final DependencyChecker checker = new DependencyChecker(pomContext, report);
-                depdendencyResult = checker.checkDependencies(jarPaths, listJarSources);
+                for (final Path tgzPath: tgzPaths) {
+                    report.format("Scanning %s \n\n", tgzPath);
+                    try (final InputStream inStream = new BufferedInputStream(new FileInputStream(tgzPath.toFile()))) {
+                        final DependencyChecker checker = new DependencyChecker(pomContext, report);
+                        depdendencyResult &= checker.checkDependencies(new TarArchiveInputStream(new GzipCompressorInputStream(inStream)), listJarSources);
+                    }
+                }
+                for (final Path zipPath: zipPaths) {
+                    report.format("Scanning %s \n\n", zipPath);
+                    try (final InputStream inStream = new BufferedInputStream(new FileInputStream(zipPath.toFile()))) {
+                        final DependencyChecker checker = new DependencyChecker(pomContext, report);
+                        depdendencyResult &= checker.checkDependencies(new ZipArchiveInputStream(inStream), listJarSources);
+                    }
+                }
                 report.format("Completed at %s\n\n", Instant.now().toString());
                 if (!depdendencyResult) {
                     log.error( "Dependency check failed, check the file ./target/dependencyReport.txt");
diff --git a/src/main/java/net/shibboleth/mvn/enforcer/impl/M2SigChecker.java b/src/main/java/net/shibboleth/mvn/enforcer/impl/M2SigChecker.java
index 5e48374..de5a625 100644
--- a/src/main/java/net/shibboleth/mvn/enforcer/impl/M2SigChecker.java
+++ b/src/main/java/net/shibboleth/mvn/enforcer/impl/M2SigChecker.java
@@ -17,6 +17,8 @@
 
 package net.shibboleth.mvn.enforcer.impl;
 
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.file.FileVisitResult;
@@ -105,7 +107,7 @@ public class M2SigChecker extends BaseSigChecker {
                 info = pom.new PomArtifact(info.getGroupId(), info.getArtifactId(), info.getVersion() + versionExtra);
             }
 
-            if (!checkSignature(file, info)) {
+            if (!checkSignature(new BufferedInputStream(new FileInputStream(file.toFile())), info)) {
                 failCount ++;
             }
             return result;
diff --git a/src/main/java/net/shibboleth/mvn/enforcer/impl/SigChecker.java b/src/main/java/net/shibboleth/mvn/enforcer/impl/SigChecker.java
index 9ddb297..2d0ae2a 100644
--- a/src/main/java/net/shibboleth/mvn/enforcer/impl/SigChecker.java
+++ b/src/main/java/net/shibboleth/mvn/enforcer/impl/SigChecker.java
@@ -18,13 +18,14 @@
 package net.shibboleth.mvn.enforcer.impl;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
-import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.List;
 
 import javax.annotation.Nonnull;
 
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
 import org.slf4j.Logger;
 
 import net.shibboleth.mvn.enforcer.impl.ParsedPom.PomArtifact;
@@ -48,42 +49,45 @@ public class SigChecker extends BaseSigChecker {
     }
     
     /** The Body of the signature test.  Are all the files what we expected?
-     * @param roots where to start looking
+     * @param archive what to look at
      * @return true if all was OK.
      */
-    public boolean testSignatures(final List<Path> roots) {
+    public boolean testSignatures(final ArchiveInputStream archive) {
         int sigFails = 0;
-        for (final Path root:roots) {
-            try {
-                sigFails += Files.list(root).mapToInt(e -> checkSignature(e)).sum();
-            } catch (final IOException e) {
-                log.error("Failed to enumerate files at {}", root, e);
-                return false;
+        try {
+            ArchiveEntry entry = null;
+            while ((entry = archive.getNextEntry()) != null) {
+                if (!archive.canReadEntryData(entry)) {
+                    log.warn("Could not read next entry from {}", archive);
+                    continue;
+                }
+                if (entry.isDirectory()) {
+                    continue;
+                }
+                else if (!entry.getName().endsWith(".jar")) {
+                    continue;
+                }
+                sigFails += checkSignature(entry.getName(), archive);
             }
-        }
-        if (sigFails != 0) {
-            getReport().format("\t%d non-exempt jar files did not have valid signatures\n", sigFails);
-        } else {
-            getReport().format("\tAll non-exempt jar files correctly signed\n");
+        } catch (final IOException e) {
+            log.error("Could not traverse archive");
+            return false;
         }
         return sigFails == 0;
     }
 
     /** Given the Path and the parent dir check the signature.
-     * @param jarFile the file to check
+     * @param jarPath the name to check
+     * @param input the stream to check
      * @return 1 if anything went wrong
      */
-    // CheckStyle: ReturnCount|CyclomaticComplexity OFF 
-    private int checkSignature(final Path jarFile) {
-        final String fileName = jarFile.getFileName().toString();
-        if (!fileName.endsWith(".jar")) {
-            return 0;
-        }
-        final Pair<String,String> name = getProjectContext().splitFileName(fileName);
+    private int checkSignature(final String jarPath, final InputStream input) {
+        final String jarName = Path.of(jarPath).getFileName().toString();
+        final Pair<String,String> name = getProjectContext().splitFileName(jarName);
         final String group = getProjectContext().getGroup(name.getFirst());
         final PomArtifact jarAsArtifact = 
                 getProjectContext().getParentPom().new PomArtifact(group, name.getFirst(), name.getSecond());
-        if (checkSignature(jarFile, jarAsArtifact)) {
+        if (checkSignature(input, jarAsArtifact)) {
             return 0;
         }
         return 1;

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list