Handle long file names in buildpack images

Fixes gh-26445
This commit is contained in:
Scott Frederick 2021-05-12 18:14:56 -05:00
parent b62905b91d
commit e9adb1ab88
3 changed files with 38 additions and 6 deletions

View File

@ -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()) {

View File

@ -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<String, TarArchive> 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<String, TarArchive> 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<ByteArrayOutputStream> 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);
}
}