fix(plugins): properly handle POSIX permissions for Docker task runner

Set POSIX file permissions when uploading/download working-dir files
from and to Docker container
This commit is contained in:
Florian Hussonnois
2025-05-15 10:21:53 +02:00
committed by Florian Hussonnois
parent 09d91034ab
commit 59e631f048
3 changed files with 112 additions and 3 deletions

View File

@@ -22,13 +22,13 @@ import io.kestra.core.runners.RunContext;
import io.kestra.core.utils.Await;
import io.kestra.core.utils.ListUtils;
import io.kestra.core.utils.RetryUtils;
import io.kestra.core.utils.UnixModeToPosixFilePermissions;
import io.kestra.plugin.scripts.exec.scripts.models.DockerOptions;
import io.micronaut.core.convert.format.ReadableBytesTypeConverter;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
@@ -44,6 +44,7 @@ import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -406,6 +407,13 @@ public class Docker extends TaskRunner<Docker.DockerTaskRunnerDetailResult> {
for (Path file: relativeWorkingDirectoryFilesPaths) {
Path resolvedFile = runContext.workingDir().resolve(file);
TarArchiveEntry entry = out.createArchiveEntry(resolvedFile.toFile(), file.toString());
// Preserve POSIX permissions if supported
try {
Set<PosixFilePermission> perms = Files.getPosixFilePermissions(resolvedFile);
entry.setMode(UnixModeToPosixFilePermissions.fromPosixFilePermissions(perms));
} catch (UnsupportedOperationException | IOException ignore) {
// Skipping unix file permission
}
out.putArchiveEntry(entry);
if (!Files.isDirectory(resolvedFile)) {
try (InputStream fis = Files.newInputStream(resolvedFile)) {
@@ -589,16 +597,21 @@ public class Docker extends TaskRunner<Docker.DockerTaskRunnerDetailResult> {
CopyArchiveFromContainerCmd copyArchiveFromContainerCmd = dockerClient.copyArchiveFromContainerCmd(execId, windowsToUnixPath(taskCommands.getWorkingDirectory().toString()));
try (InputStream is = copyArchiveFromContainerCmd.exec();
TarArchiveInputStream tar = new TarArchiveInputStream(is)) {
ArchiveEntry entry;
TarArchiveEntry entry;
while ((entry = tar.getNextEntry()) != null) {
// each entry contains the working directory as the first part, we need to remove it
Path extractTo = runContext.workingDir().resolve(Path.of(entry.getName().substring(runContext.workingDir().id().length() +1)));
Path extractTo = runContext.workingDir().resolve(Path.of(entry.getName().substring(runContext.workingDir().id().length() + 1)));
if (entry.isDirectory()) {
if (!Files.exists(extractTo)) {
Files.createDirectories(extractTo);
}
} else {
Files.copy(tar, extractTo, StandardCopyOption.REPLACE_EXISTING);
try {
Files.setPosixFilePermissions(extractTo, UnixModeToPosixFilePermissions.toPosixPermissions(entry.getMode()));
} catch (UnsupportedOperationException | IOException e) {
// File system does not support POSIX permissions (e.g., Windows)
}
}
}
}