Skip to content

Commit

Permalink
fix: file ownership of files copied into the container (#2007)
Browse files Browse the repository at this point in the history
Revert to using `cat`/`tar` to copy files/folders into the container.
  • Loading branch information
mayeut authored Sep 16, 2024
1 parent 01ecd4e commit 8c42e79
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
38 changes: 35 additions & 3 deletions cibuildwheel/oci_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
import platform
import shlex
import shutil
import subprocess
import sys
import typing
Expand Down Expand Up @@ -169,6 +170,9 @@ def __init__(
self.cwd = cwd
self.name: str | None = None
self.engine = engine
self.host_tar_format = ""
if sys.platform.startswith("darwin"):
self.host_tar_format = "--format gnutar"

def _get_platform_args(self, *, oci_platform: OCIPlatform | None = None) -> tuple[str, str]:
if oci_platform is None:
Expand Down Expand Up @@ -311,10 +315,38 @@ def __exit__(
def copy_into(self, from_path: Path, to_path: PurePath) -> None:
if from_path.is_dir():
self.call(["mkdir", "-p", to_path])
call(self.engine.name, "cp", f"{from_path}/.", f"{self.name}:{to_path}")
subprocess.run(
f"tar -c {self.host_tar_format} -f - . | {self.engine.name} exec -i {self.name} tar --no-same-owner -xC {shell_quote(to_path)} -f -",
shell=True,
check=True,
cwd=from_path,
)
else:
self.call(["mkdir", "-p", to_path.parent])
call(self.engine.name, "cp", from_path, f"{self.name}:{to_path}")
exec_process: subprocess.Popen[bytes]
with subprocess.Popen(
[
self.engine.name,
"exec",
"-i",
str(self.name),
"sh",
"-c",
f"cat > {shell_quote(to_path)}",
],
stdin=subprocess.PIPE,
) as exec_process:
assert exec_process.stdin
with open(from_path, "rb") as from_file:
# Bug in mypy, https://github.com/python/mypy/issues/15031
shutil.copyfileobj(from_file, exec_process.stdin) # type: ignore[misc]

exec_process.stdin.close()
exec_process.wait()

if exec_process.returncode:
raise subprocess.CalledProcessError(
exec_process.returncode, exec_process.args, None, None
)

def copy_out(self, from_path: PurePath, to_path: Path) -> None:
# note: we assume from_path is a dir
Expand Down
14 changes: 14 additions & 0 deletions unit_test/oci_container_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ def test_file_operation(tmp_path: Path, container_engine):

container.copy_into(original_test_file, dst_file)

owner = container.call(["stat", "-c", "%u:%g", dst_file], capture_output=True).strip()
assert owner == "0:0"

output = container.call(["cat", dst_file], capture_output=True)
assert test_binary_data == bytes(output, encoding="utf8", errors="surrogateescape")

Expand All @@ -266,6 +269,12 @@ def test_dir_operations(tmp_path: Path, container_engine):
dst_file = dst_dir / "test.dat"
container.copy_into(test_dir, dst_dir)

owner = container.call(["stat", "-c", "%u:%g", dst_dir], capture_output=True).strip()
assert owner == "0:0"

owner = container.call(["stat", "-c", "%u:%g", dst_file], capture_output=True).strip()
assert owner == "0:0"

output = container.call(["cat", dst_file], capture_output=True)
assert test_binary_data == bytes(output, encoding="utf8", errors="surrogateescape")

Expand All @@ -276,6 +285,11 @@ def test_dir_operations(tmp_path: Path, container_engine):
new_test_dir = tmp_path / "test_dir_new"
container.copy_out(dst_dir, new_test_dir)

assert os.getuid() == new_test_dir.stat().st_uid
assert os.getgid() == new_test_dir.stat().st_gid
assert os.getuid() == (new_test_dir / "test.dat").stat().st_uid
assert os.getgid() == (new_test_dir / "test.dat").stat().st_gid

assert test_binary_data == (new_test_dir / "test.dat").read_bytes()


Expand Down

0 comments on commit 8c42e79

Please # to comment.