Skip to content

Commit

Permalink
Fixes for alpine (UKGovernmentBEIS#366)
Browse files Browse the repository at this point in the history
* Fixes for alpine

* Fixes for alpine and a test

* ruff
  • Loading branch information
art-dsit authored Sep 10, 2024
1 parent 8806522 commit 123ec9b
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 12 deletions.
22 changes: 12 additions & 10 deletions src/inspect_ai/util/_sandbox/docker/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ async def write_file(self, file: str, contents: str | bytes) -> None:
local_tmpfile.close() # this will also delete the file

if not hasattr(self, "_docker_user"):
uid = (await self.exec(["id", "--user"])).stdout.strip()
gid = (await self.exec(["id", "--group"])).stdout.strip()
uid = (await self.exec(["id", "-u"])).stdout.strip()
gid = (await self.exec(["id", "-g"])).stdout.strip()
self._docker_user = (uid, gid)

await compose_command(
Expand All @@ -296,17 +296,17 @@ async def write_file(self, file: str, contents: str | bytes) -> None:
project=self._project,
)

res_cp = await self.exec(
["cp", "--no-target-directory", "--", container_tmpfile, file]
)

await self.exec(["rm", container_tmpfile])
res_cp = await self.exec(["cp", "-T", "--", container_tmpfile, file])

if res_cp.returncode != 0:
if "Permission denied" in res_cp.stderr:
error_string = f"Permission was denied. Failed to copy temporary file. Error details: {res_cp.stderr};"
ls_result = await self.exec(["ls", "-la", "."])
error_string = f"Permission was denied. Failed to copy temporary file. Error details: {res_cp.stderr}; ls -la: {ls_result.stdout}; {self._docker_user=}"
raise PermissionError(error_string)
elif "cannot overwrite directory" in res_cp.stderr:
elif (
"cannot overwrite directory" in res_cp.stderr
or "is a directory" in res_cp.stderr
):
raise IsADirectoryError(
f"Failed to write file: {file} because it is a directory already"
)
Expand All @@ -315,6 +315,8 @@ async def write_file(self, file: str, contents: str | bytes) -> None:
f"failed to copy temporary file during write_file: {res_cp}"
)

await self.exec(["rm", container_tmpfile])

@overload
async def read_file(self, file: str, text: Literal[True] = True) -> str: ...

Expand Down Expand Up @@ -376,7 +378,7 @@ def container_file(self, file: str) -> str:
async def container_working_dir(
service: str, project: ComposeProject, default: str = "/"
) -> str:
result = await compose_exec([service, "bash", "-c", "pwd"], project)
result = await compose_exec([service, "sh", "-c", "pwd"], project)
if result.success:
return result.stdout.strip()
else:
Expand Down
4 changes: 2 additions & 2 deletions src/inspect_ai/util/_sandbox/self_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ async def test_exec_as_user(sandbox_env: SandboxEnvironment) -> None:
try:
# Create a new user
add_user_result = await sandbox_env.exec(
["useradd", "-m", username], user="root"
["adduser", "--disabled-password", username], user="root"
)
assert add_user_result.success, f"Failed to add user: {add_user_result.stderr}"

Expand Down Expand Up @@ -225,7 +225,7 @@ async def test_cwd_unspecified(sandbox_env: SandboxEnvironment) -> None:

async def test_cwd_custom(sandbox_env: SandboxEnvironment) -> None:
current_dir_contents = (await sandbox_env.exec(["ls"], cwd="/usr/bin")).stdout
assert "man" in current_dir_contents
assert "env" in current_dir_contents


async def test_cwd_relative(sandbox_env: SandboxEnvironment) -> None:
Expand Down
2 changes: 2 additions & 0 deletions tests/tools/docker-compose-context-alpine/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM alpine:latest
RUN adduser -u 1111 --disabled-password nonroot
12 changes: 12 additions & 0 deletions tests/tools/test_sandbox_compose_alpine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
default:
build:
context: docker-compose-context-alpine
dockerfile: Dockerfile
command: "tail -f /dev/null"
user: nonroot
working_dir: /home/nonroot
init: true
network_mode: none
stop_grace_period: 1s

21 changes: 21 additions & 0 deletions tests/tools/test_sandbox_docker_and_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ async def test_self_check_docker_custom_nonroot(request) -> None:
return await check_results_of_self_check(task_name, envs_dict)


@skip_if_no_docker
@pytest.mark.slow
async def test_self_check_docker_custom_nonroot_alpine(request) -> None:
task_name = f"{__name__}_{request.node.name}_docker_nonroot_alpine"

# Alpine has busybox which is has a bunch of stuff "missing" if you are used to GNU.
config_file = str(Path(__file__) / ".." / "test_sandbox_compose_alpine.yaml")

await DockerSandboxEnvironment.task_init(task_name=task_name, config=config_file)
envs_dict = await DockerSandboxEnvironment.sample_init(
task_name=task_name, config=config_file, metadata={}
)

return await check_results_of_self_check(
# alpine busybox is happy to overwrite a readonly file with cp
task_name,
envs_dict,
["test_write_file_without_permissions"],
)


@skip_if_no_docker
@pytest.mark.slow
async def test_self_check_docker_default_root(request) -> None:
Expand Down

0 comments on commit 123ec9b

Please sign in to comment.