From e9adb1ab88d2778b65e8643e008814c085111649 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Wed, 12 May 2021 18:14:56 -0500 Subject: [PATCH] Handle long file names in buildpack images Fixes gh-26445 --- .../platform/build/ImageBuildpack.java | 1 + .../platform/build/ImageBuildpackTests.java | 43 +++++++++++++++--- .../boot/buildpack/platform/build/layer.tar | Bin 3072 -> 0 bytes 3 files changed, 38 insertions(+), 6 deletions(-) delete mode 100644 spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/layer.tar diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageBuildpack.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageBuildpack.java index 45b03813e7..c64d5c24f5 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageBuildpack.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/main/java/org/springframework/boot/buildpack/platform/build/ImageBuildpack.java @@ -124,6 +124,7 @@ final class ImageBuildpack implements Buildpack { private void copyLayerTar(Path path, OutputStream out) throws IOException { try (TarArchiveInputStream tarIn = new TarArchiveInputStream(Files.newInputStream(path)); TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) { + tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); TarArchiveEntry entry = tarIn.getNextTarEntry(); while (entry != null) { if (entry.isFile()) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ImageBuildpackTests.java b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ImageBuildpackTests.java index ffb2230451..7670840852 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ImageBuildpackTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/java/org/springframework/boot/buildpack/platform/build/ImageBuildpackTests.java @@ -21,9 +21,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Random; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.invocation.InvocationOnMock; @@ -31,10 +34,10 @@ import org.springframework.boot.buildpack.platform.docker.type.Image; import org.springframework.boot.buildpack.platform.io.IOBiConsumer; import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.boot.buildpack.platform.json.AbstractJsonTests; -import org.springframework.util.FileCopyUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willAnswer; @@ -48,6 +51,15 @@ import static org.mockito.Mockito.mock; */ class ImageBuildpackTests extends AbstractJsonTests { + private String longFilePath; + + @BeforeEach + void setUp() { + StringBuilder path = new StringBuilder(); + new Random().ints('a', 'z' + 1).limit(100).forEach((i) -> path.append((char) i)); + this.longFilePath = path.toString(); + } + @Test void resolveWhenFullyQualifiedReferenceReturnsBuilder() throws Exception { Image image = Image.of(getContent("buildpack-image.json")); @@ -108,13 +120,31 @@ class ImageBuildpackTests extends AbstractJsonTests { assertThat(buildpack).isNull(); } - private Object withMockLayers(InvocationOnMock invocation) throws Exception { - IOBiConsumer consumer = invocation.getArgument(1); - TarArchive archive = (out) -> FileCopyUtils.copy(getClass().getResourceAsStream("layer.tar"), out); - consumer.accept("test", archive); + private Object withMockLayers(InvocationOnMock invocation) { + try { + IOBiConsumer consumer = invocation.getArgument(1); + TarArchive archive = (out) -> { + try (TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) { + tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX); + writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml"); + writeTarEntry(tarOut, "/cnb/buildpacks/example_buildpack/0.0.1/" + this.longFilePath); + tarOut.finish(); + } + }; + consumer.accept("test", archive); + } + catch (IOException ex) { + fail("Error writing mock layers", ex); + } return null; } + private void writeTarEntry(TarArchiveOutputStream tarOut, String name) throws IOException { + TarArchiveEntry entry = new TarArchiveEntry(name); + tarOut.putArchiveEntry(entry); + tarOut.closeArchiveEntry(); + } + private void assertHasExpectedLayers(Buildpack buildpack) throws IOException { List layers = new ArrayList<>(); buildpack.apply((layer) -> { @@ -132,7 +162,8 @@ class ImageBuildpackTests extends AbstractJsonTests { entry = tar.getNextTarEntry(); } } - assertThat(names).containsExactly("etc/apt/sources.list"); + assertThat(names).containsExactlyInAnyOrder("cnb/buildpacks/example_buildpack/0.0.1/buildpack.toml", + "cnb/buildpacks/example_buildpack/0.0.1/" + this.longFilePath); } } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/layer.tar b/spring-boot-project/spring-boot-tools/spring-boot-buildpack-platform/src/test/resources/org/springframework/boot/buildpack/platform/build/layer.tar deleted file mode 100644 index e6b99b0181429b797a42582daa48f3253ce4c5ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3072 zcmeHGOAf*y5M}KtxPa}@LP@+0MG{HuCop5;?WHzunwZqox{=v1km1ee&2wl=wzC09 z&`L3wZFx?wOh^z=sS31a$%9HTu6C~L2~QDCNF{B}wQO!H-jDvf#J?GF*Bw~NKZsh_ zO#>7E4d~4OFIM2ie;g=S7mKTp`0c!to*OBbx_{lFmP`HDLM8q;YjRB^f3E+tYxxCn zJe8#h_Tq1@pq6^1!VXY4;CPc?Oy5j5}J^(q=csA(bcfg{v6g=MF Tqpewi9Fr%ICy*!bj}v$RnnR7A