Handle long file names in buildpack images

Fixes gh-26445
pull/26446/head
Scott Frederick 4 years ago
parent b62905b91d
commit e9adb1ab88

@ -124,6 +124,7 @@ final class ImageBuildpack implements Buildpack {
private void copyLayerTar(Path path, OutputStream out) throws IOException { private void copyLayerTar(Path path, OutputStream out) throws IOException {
try (TarArchiveInputStream tarIn = new TarArchiveInputStream(Files.newInputStream(path)); try (TarArchiveInputStream tarIn = new TarArchiveInputStream(Files.newInputStream(path));
TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) { TarArchiveOutputStream tarOut = new TarArchiveOutputStream(out)) {
tarOut.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
TarArchiveEntry entry = tarIn.getNextTarEntry(); TarArchiveEntry entry = tarIn.getNextTarEntry();
while (entry != null) { while (entry != null) {
if (entry.isFile()) { if (entry.isFile()) {

@ -21,9 +21,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 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.junit.jupiter.api.Test;
import org.mockito.invocation.InvocationOnMock; 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.IOBiConsumer;
import org.springframework.boot.buildpack.platform.io.TarArchive; import org.springframework.boot.buildpack.platform.io.TarArchive;
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; 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.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer; import static org.mockito.BDDMockito.willAnswer;
@ -48,6 +51,15 @@ import static org.mockito.Mockito.mock;
*/ */
class ImageBuildpackTests extends AbstractJsonTests { 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 @Test
void resolveWhenFullyQualifiedReferenceReturnsBuilder() throws Exception { void resolveWhenFullyQualifiedReferenceReturnsBuilder() throws Exception {
Image image = Image.of(getContent("buildpack-image.json")); Image image = Image.of(getContent("buildpack-image.json"));
@ -108,13 +120,31 @@ class ImageBuildpackTests extends AbstractJsonTests {
assertThat(buildpack).isNull(); assertThat(buildpack).isNull();
} }
private Object withMockLayers(InvocationOnMock invocation) throws Exception { private Object withMockLayers(InvocationOnMock invocation) {
IOBiConsumer<String, TarArchive> consumer = invocation.getArgument(1); try {
TarArchive archive = (out) -> FileCopyUtils.copy(getClass().getResourceAsStream("layer.tar"), out); IOBiConsumer<String, TarArchive> consumer = invocation.getArgument(1);
consumer.accept("test", archive); 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; 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 { private void assertHasExpectedLayers(Buildpack buildpack) throws IOException {
List<ByteArrayOutputStream> layers = new ArrayList<>(); List<ByteArrayOutputStream> layers = new ArrayList<>();
buildpack.apply((layer) -> { buildpack.apply((layer) -> {
@ -132,7 +162,8 @@ class ImageBuildpackTests extends AbstractJsonTests {
entry = tar.getNextTarEntry(); 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);
} }
} }

Loading…
Cancel
Save