Skip to content

Commit

Permalink
[Core] Sanitize filename before using it as docker image tag. Fix #1069
Browse files Browse the repository at this point in the history
… (#1127)

* fix #1069

* uncomment skips

* use importlib to check package

* better code

---------

Co-authored-by: Chi Wang <wang.chi@microsoft.com>
  • Loading branch information
2 people authored and joshkyh committed Jan 17, 2024
1 parent 3320f80 commit 2dd11e9
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 10 deletions.
28 changes: 26 additions & 2 deletions autogen/code_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import pathlib
import re
import string
import subprocess
import sys
import time
Expand Down Expand Up @@ -224,6 +225,29 @@ def _cmd(lang):
raise NotImplementedError(f"{lang} not recognized in code execution")


def _sanitize_filename_for_docker_tag(filename: str) -> str:
"""Convert a filename to a valid docker tag.
See https://docs.docker.com/engine/reference/commandline/tag/ for valid tag
format.
Args:
filename (str): The filename to be converted.
Returns:
str: The sanitized Docker tag.
"""
# Replace any character not allowed with an underscore
allowed_chars = set(string.ascii_letters + string.digits + "_.-")
sanitized = "".join(char if char in allowed_chars else "_" for char in filename)

# Ensure it does not start with a period or a dash
if sanitized.startswith(".") or sanitized.startswith("-"):
sanitized = "_" + sanitized[1:]

# Truncate if longer than 128 characters
return sanitized[:128]


def execute_code(
code: Optional[str] = None,
timeout: Optional[int] = None,
Expand Down Expand Up @@ -379,7 +403,7 @@ def execute_code(
cmd = [
"sh",
"-c",
f"{_cmd(lang)} {filename}; exit_code=$?; echo -n {exit_code_str}; echo -n $exit_code; echo {exit_code_str}",
f'{_cmd(lang)} "{filename}"; exit_code=$?; echo -n {exit_code_str}; echo -n $exit_code; echo {exit_code_str}',
]
# create a docker container
container = client.containers.run(
Expand All @@ -403,7 +427,7 @@ def execute_code(
# get the container logs
logs = container.logs().decode("utf-8").rstrip()
# commit the image
tag = filename.replace("/", "")
tag = _sanitize_filename_for_docker_tag(filename)
container.commit(repository="python", tag=tag)
# remove the container
container.remove()
Expand Down
40 changes: 32 additions & 8 deletions test/test_code.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import importlib.metadata
import os
import sys
import unittest
Expand All @@ -22,6 +23,21 @@
here = os.path.abspath(os.path.dirname(__file__))


def is_package_installed(package_name):
"""Check if a package is installed. This is a preferred way to check if a
package is installed or not than doing a try-catch around an import
because it avoids name conflict with local modules and
code execution in the imported module."""
try:
importlib.metadata.version(package_name)
return True
except importlib.metadata.PackageNotFoundError:
return False


docker_package_installed = is_package_installed("docker")


# def test_find_code():
# try:
# import openai
Expand Down Expand Up @@ -293,10 +309,6 @@ def scrape(url):
assert len(codeblocks) == 1 and codeblocks[0] == ("", "source setup.sh")


@pytest.mark.skipif(
sys.platform in ["darwin"],
reason="do not run on MacOS",
)
def test_execute_code(use_docker=None):
try:
import docker
Expand Down Expand Up @@ -338,15 +350,27 @@ def test_execute_code(use_docker=None):
assert isinstance(image, str) or docker is None or os.path.exists("/.dockerenv") or use_docker is False


@pytest.mark.skipif(docker_package_installed is False, reason="docker package not installed")
def test_execute_code_with_custom_filename_on_docker():
exit_code, msg, image = execute_code("print('hello world')", filename="tmp/codetest.py", use_docker=True)
assert exit_code == 0 and msg == "hello world\n", msg
assert image == "python:tmp_codetest.py"


@pytest.mark.skipif(docker_package_installed is False, reason="docker package not installed")
def test_execute_code_with_misformed_filename_on_docker():
exit_code, msg, image = execute_code(
"print('hello world')", filename="tmp/codetest.py (some extra information)", use_docker=True
)
assert exit_code == 0 and msg == "hello world\n", msg
assert image == "python:tmp_codetest.py__some_extra_information_"


def test_execute_code_raises_when_code_and_filename_are_both_none():
with pytest.raises(AssertionError):
execute_code(code=None, filename=None)


@pytest.mark.skipif(
sys.platform in ["darwin"],
reason="do not run on MacOS",
)
def test_execute_code_nodocker():
test_execute_code(use_docker=False)

Expand Down

0 comments on commit 2dd11e9

Please sign in to comment.