This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 08e25ae003 NIFI-14759 Handle out-of-order File Entries in NarUnpacker
(#10270)
08e25ae003 is described below
commit 08e25ae0034c03503de7ff961f706c023659ee0d
Author: Pierre Villard <[email protected]>
AuthorDate: Thu Sep 4 18:28:54 2025 +0200
NIFI-14759 Handle out-of-order File Entries in NarUnpacker (#10270)
Signed-off-by: David Handermann <[email protected]>
---
.../java/org/apache/nifi/nar/NarUnpackerTest.java | 36 ++++++++++++++++++++++
.../main/java/org/apache/nifi/nar/NarUnpacker.java | 6 ++++
2 files changed, 42 insertions(+)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
index db11aa854b..d62cf4dc01 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/test/java/org/apache/nifi/nar/NarUnpackerTest.java
@@ -23,8 +23,10 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -38,6 +40,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
import java.util.stream.Stream;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
@@ -194,6 +198,38 @@ public class NarUnpackerTest {
assertTrue(extensionMapping.isEmpty());
}
+ @Test
+ public void testUnpackNarHandlesManifestBeforeMetaInfDirectory(@TempDir
final Path tempDir) throws IOException {
+ // Create a minimal NAR with problematic entry order: MANIFEST first,
then META-INF/ directory
+ final File narFile = tempDir.resolve("bad-order.nar").toFile();
+ try (FileOutputStream fos = new FileOutputStream(narFile);
+ JarOutputStream jos = new JarOutputStream(fos)) {
+ // MANIFEST first (without prior META-INF/ dir entry)
+ final JarEntry manifestEntry = new
JarEntry("META-INF/MANIFEST.MF");
+ jos.putNextEntry(manifestEntry);
+ final byte[] manifestBytes = (
+ "Manifest-Version: 1.0\n" +
+ "NAR-Group: org.example\n" +
+ "NAR-Id: test-nar\n" +
+ "NAR-Version: 1.0.0\n\n"
+ ).getBytes(StandardCharsets.UTF_8);
+ jos.write(manifestBytes);
+ jos.closeEntry();
+
+ // META-INF/ directory entry added after
+ final JarEntry metaInfDir = new JarEntry("META-INF/");
+ jos.putNextEntry(metaInfDir);
+ jos.closeEntry();
+ }
+
+ final File baseWorkingDir = tempDir.resolve("work").toFile();
+
+ // Should unpack successfully despite directory entry order
+ final File unpackedDir = NarUnpacker.unpackNar(narFile,
baseWorkingDir, true, NarUnpackMode.UNPACK_INDIVIDUAL_JARS);
+ final File manifestOut = new File(unpackedDir, "META-INF/MANIFEST.MF");
+ assertTrue(manifestOut.isFile(), "Manifest should be unpacked even
when META-INF/ entry comes later");
+ }
+
private NiFiProperties loadSpecifiedProperties(final Map<String, String>
others) {
String filePath;
try {
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarUnpacker.java
b/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarUnpacker.java
index b9881d6f86..18ff8cf78e 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarUnpacker.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/NarUnpacker.java
@@ -595,6 +595,12 @@ public final class NarUnpacker {
* if the file could not be created.
*/
private static void makeFile(final InputStream inputStream, final File
file) throws IOException {
+ // Ensure parent directories exist to handle archives where directory
entries
+ // appear after file entries (e.g., after jarsigner has reordered
entries)
+ final File parent = file.getParentFile();
+ if (parent != null) {
+ Files.createDirectories(parent.toPath());
+ }
try (final InputStream in = inputStream;
final FileOutputStream fos = new FileOutputStream(file)) {
byte[] bytes = new byte[65536];