From 7fc1da194df2cc00cd5fd31345770a278b26d17b Mon Sep 17 00:00:00 2001 From: Sun Dapeng Date: Wed, 29 Jul 2026 20:20:23 +0800 Subject: [PATCH 1/2] [filesystem] Fix nested META-INF/versions in filesystem impl jars --- paimon-filesystems/paimon-azure-impl/pom.xml | 7 ++++++- paimon-filesystems/paimon-cosn-impl/pom.xml | 7 ++++++- paimon-filesystems/paimon-gs-impl/pom.xml | 7 ++++++- paimon-filesystems/paimon-oss-impl/pom.xml | 7 ++++++- paimon-filesystems/paimon-s3-impl/pom.xml | 7 ++++++- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/paimon-filesystems/paimon-azure-impl/pom.xml b/paimon-filesystems/paimon-azure-impl/pom.xml index a4cfcfd1811f..828fca5929b2 100644 --- a/paimon-filesystems/paimon-azure-impl/pom.xml +++ b/paimon-filesystems/paimon-azure-impl/pom.xml @@ -146,6 +146,12 @@ + + + + @@ -177,7 +183,6 @@ mime.types mozilla/** META-INF/maven/** - META-INF/versions/11/META-INF/maven/** META-INF/LICENSE.txt diff --git a/paimon-filesystems/paimon-cosn-impl/pom.xml b/paimon-filesystems/paimon-cosn-impl/pom.xml index 838e1a62a154..df94305a2bd7 100644 --- a/paimon-filesystems/paimon-cosn-impl/pom.xml +++ b/paimon-filesystems/paimon-cosn-impl/pom.xml @@ -155,6 +155,12 @@ + + + + @@ -187,7 +193,6 @@ mime.types mozilla/** META-INF/maven/** - META-INF/versions/11/META-INF/maven/** META-INF/LICENSE.txt diff --git a/paimon-filesystems/paimon-gs-impl/pom.xml b/paimon-filesystems/paimon-gs-impl/pom.xml index 5bcc99520f38..41c00859d1c5 100644 --- a/paimon-filesystems/paimon-gs-impl/pom.xml +++ b/paimon-filesystems/paimon-gs-impl/pom.xml @@ -272,6 +272,12 @@ + + + + @@ -303,7 +309,6 @@ mime.types mozilla/** META-INF/maven/** - META-INF/versions/11/META-INF/maven/** META-INF/LICENSE.txt diff --git a/paimon-filesystems/paimon-oss-impl/pom.xml b/paimon-filesystems/paimon-oss-impl/pom.xml index 9a0a28f45ad3..308cfe3f6f83 100644 --- a/paimon-filesystems/paimon-oss-impl/pom.xml +++ b/paimon-filesystems/paimon-oss-impl/pom.xml @@ -162,6 +162,12 @@ + + + + @@ -194,7 +200,6 @@ mime.types mozilla/** META-INF/maven/** - META-INF/versions/11/META-INF/maven/** META-INF/LICENSE.txt diff --git a/paimon-filesystems/paimon-s3-impl/pom.xml b/paimon-filesystems/paimon-s3-impl/pom.xml index 886af231f42d..761b0f6d906c 100644 --- a/paimon-filesystems/paimon-s3-impl/pom.xml +++ b/paimon-filesystems/paimon-s3-impl/pom.xml @@ -260,6 +260,12 @@ + + + + @@ -291,7 +297,6 @@ mime.types mozilla/** META-INF/maven/** - META-INF/versions/11/META-INF/maven/** META-INF/LICENSE.txt From 368936a1aca50a3f98bd7ff7929fbb49ca6e64db Mon Sep 17 00:00:00 2001 From: Sun Dapeng Date: Wed, 29 Jul 2026 21:21:19 +0800 Subject: [PATCH 2/2] [build] Reject nested META-INF in multi-release directories in JarFileChecker --- .../tools/ci/licensecheck/JarFileChecker.java | 40 ++++++++++-------- .../ci/licensecheck/JarFileCheckerTest.java | 41 +++++++++++++++++++ 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java b/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java index ac5785ec101a..06f33273e289 100644 --- a/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java +++ b/tools/ci/paimon-ci-tools/src/main/java/org/apache/paimon/tools/ci/licensecheck/JarFileChecker.java @@ -81,6 +81,8 @@ static int checkJar(Path file) throws Exception { getNumLicenseFilesOutsideMetaInfDirectory(file, fileSystem.getPath("/")); numSevereIssues += getFilesWithIncompatibleLicenses(file, fileSystem.getPath("/")); + + numSevereIssues += getNumNestedMetaInfDirectories(file, fileSystem.getPath("/")); } return numSevereIssues; } @@ -215,7 +217,6 @@ private static int findNonBinaryFilesContainingText( path -> !pathStartsWith( path, "/META-INF/maven/javax.xml.bind/jaxb-api")) - .filter(path -> !isJavaxManifest(jar, path)) // dual-licensed under GPL 2 and EPL 2.0 // contained in sql-avro-confluent-registry .filter(path -> !pathStartsWith(path, "/org/glassfish/jersey/internal")) @@ -306,6 +307,27 @@ private static int getNumLicenseFilesOutsideMetaInfDirectory(Path jar, Path jarR } } + private static int getNumNestedMetaInfDirectories(Path jar, Path jarRoot) throws IOException { + // a nested META-INF below META-INF/versions indicates that another jar was + // unpacked/shaded as-is into the multi-release directory; the nested multi-release + // metadata is not resolvable at runtime and breaks tools scanning the unpacked + // classes (e.g., JaCoCo fails on duplicate class names) + final Pattern nestedMetaInf = Pattern.compile("^/?META-INF/versions/[^/]+/META-INF/?$"); + try (Stream files = Files.walk(jarRoot)) { + final List filesWithIssues = + files.map(Path::toString) + .filter(path -> nestedMetaInf.matcher(path).matches()) + .collect(Collectors.toList()); + for (String fileWithIssue : filesWithIssues) { + LOG.error( + "Jar file {} contains a nested META-INF directory in a multi-release directory: {}", + jar, + fileWithIssue); + } + return filesWithIssues.size(); + } + } + private static String getFileName(Path path) { return path.getFileName().toString().toLowerCase(); } @@ -314,26 +336,10 @@ private static boolean pathStartsWith(Path file, String path) { return file.startsWith(file.getFileSystem().getPath(path)); } - private static boolean equals(Path file, String path) { - return file.equals(file.getFileSystem().getPath(path)); - } - private static boolean isNoClassFile(Path file) { return !getFileName(file).endsWith(".class"); } - private static boolean isJavaxManifest(Path jar, Path potentialManifestFile) { - try { - return equals(potentialManifestFile, "/META-INF/versions/11/META-INF/MANIFEST.MF") - && readFile(potentialManifestFile).contains("Specification-Title: jaxb-api"); - } catch (IOException e) { - throw new RuntimeException( - String.format( - "Error while reading file %s from jar %s.", potentialManifestFile, jar), - e); - } - } - private static String readFile(Path file) throws IOException { return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); } diff --git a/tools/ci/paimon-ci-tools/src/test/java/org/apache/paimon/tools/ci/licensecheck/JarFileCheckerTest.java b/tools/ci/paimon-ci-tools/src/test/java/org/apache/paimon/tools/ci/licensecheck/JarFileCheckerTest.java index 2b3165b0c853..7ace8b7a0552 100644 --- a/tools/ci/paimon-ci-tools/src/test/java/org/apache/paimon/tools/ci/licensecheck/JarFileCheckerTest.java +++ b/tools/ci/paimon-ci-tools/src/test/java/org/apache/paimon/tools/ci/licensecheck/JarFileCheckerTest.java @@ -298,6 +298,47 @@ void testIgnoreDualLicensedJavaxFiles(@TempDir Path tempDir) throws Exception { .isEqualTo(0); } + @Test + void testRejectedOnNestedMetaInfInMultiReleaseDirectory(@TempDir Path tempDir) + throws Exception { + assertThat( + JarFileChecker.checkJar( + createJar( + tempDir, + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry( + "Manifest-Version: 1.0", + Arrays.asList( + "META-INF", + "versions", + "11", + "META-INF", + "MANIFEST.MF"))))) + .isEqualTo(1); + } + + @Test + void testAcceptedOnRegularMultiReleaseContent(@TempDir Path tempDir) throws Exception { + assertThat( + JarFileChecker.checkJar( + createJar( + tempDir, + Entry.fileEntry(VALID_NOTICE_CONTENTS, VALID_NOTICE_PATH), + Entry.fileEntry(VALID_LICENSE_CONTENTS, VALID_LICENSE_PATH), + Entry.fileEntry( + "some java 11 resource", + Arrays.asList( + "META-INF", + "versions", + "11", + "javax", + "xml", + "bind", + "Messages.properties"))))) + .isEqualTo(0); + } + private static class Entry { final String contents; final List path;