summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Knight <james.d.knight@live.com>2021-09-16 03:36:40 -0400
committerGitHub <noreply@github.com>2021-09-16 08:36:40 +0100
commit51cc218e71949e90ab7982bbb12a475fcbb90613 (patch)
tree79367ea85f16ddfefc23b6758a67dce69978252d
parent3c1c29ab609bf4471d5bf5598585cd76fa890c71 (diff)
downloadtox-git-51cc218e71949e90ab7982bbb12a475fcbb90613.tar.gz
venv: do not prepend a truncated shebang interpreter (#2203)
-rw-r--r--docs/changelog/2208.bugfix.rst2
-rw-r--r--docs/config.rst4
-rw-r--r--src/tox/venv.py10
-rw-r--r--tests/unit/test_venv.py13
4 files changed, 24 insertions, 5 deletions
diff --git a/docs/changelog/2208.bugfix.rst b/docs/changelog/2208.bugfix.rst
new file mode 100644
index 00000000..699f1819
--- /dev/null
+++ b/docs/changelog/2208.bugfix.rst
@@ -0,0 +1,2 @@
+Prevent tox from using a truncated interpreter when using
+``TOX_LIMITED_SHEBANG`` -- by :user:`jdknight`.
diff --git a/docs/config.rst b/docs/config.rst
index ada5f19e..da10f38c 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -1097,9 +1097,9 @@ Handle interpreter directives with long lengths
For systems supporting executable text files (scripts with a shebang), the
system will attempt to parse the interpreter directive to determine the program
to execute on the target text file. When ``tox`` prepares a virtual environment
-in a file container which has a large length (e.x. using Jenkins Pipelines), the
+in a file container which has a large length (e.g. using Jenkins Pipelines), the
system might not be able to invoke shebang scripts which define interpreters
-beyond system limits (e.x. Linux as a limit of 128; ``BINPRM_BUF_SIZE``). To
+beyond system limits (e.g. Linux has a limit of 128; ``BINPRM_BUF_SIZE``). To
workaround an environment which suffers from an interpreter directive limit, a
user can bypass the system's interpreter parser by defining the
``TOX_LIMITED_SHEBANG`` environment variable before invoking ``tox``::
diff --git a/src/tox/venv.py b/src/tox/venv.py
index a28fd83e..7ba743f8 100644
--- a/src/tox/venv.py
+++ b/src/tox/venv.py
@@ -19,6 +19,9 @@ from tox.util.path import ensure_empty_dir
from .config import DepConfig
+#: maximum parsed shebang interpreter length (see: prepend_shebang_interpreter)
+MAXINTERP = 2048
+
class CreationConfig:
def __init__(
@@ -672,7 +675,7 @@ def prepend_shebang_interpreter(args):
#
# When preparing virtual environments in a file container which has large
# length, the system might not be able to invoke shebang scripts which
- # define interpreters beyond system limits (e.x. Linux as a limit of 128;
+ # define interpreters beyond system limits (e.g. Linux has a limit of 128;
# BINPRM_BUF_SIZE). This method can be used to check if the executable is
# a script containing a shebang line. If so, extract the interpreter (and
# possible optional argument) and prepend the values to the provided
@@ -682,8 +685,9 @@ def prepend_shebang_interpreter(args):
try:
with open(args[0], "rb") as f:
if f.read(1) == b"#" and f.read(1) == b"!":
- MAXINTERP = 2048
- interp = f.readline(MAXINTERP).rstrip().decode("UTF-8")
+ interp = f.readline(MAXINTERP + 1).rstrip().decode("UTF-8")
+ if len(interp) > MAXINTERP: # avoid a truncated interpreter
+ return args
interp_args = interp.split(None, 1)[:2]
return interp_args + args
except (UnicodeDecodeError, IOError):
diff --git a/tests/unit/test_venv.py b/tests/unit/test_venv.py
index 22e76cf5..37c471f3 100644
--- a/tests/unit/test_venv.py
+++ b/tests/unit/test_venv.py
@@ -9,6 +9,7 @@ import tox
from tox.interpreters import NoInterpreterInfo
from tox.session.commands.run.sequential import installpkg, runtestenv
from tox.venv import (
+ MAXINTERP,
CreationConfig,
VirtualEnv,
getdigest,
@@ -1149,6 +1150,18 @@ def test_tox_testenv_interpret_shebang_long_example(tmpdir):
assert args == expected + base_args
+@pytest.mark.skipif("sys.platform == 'win32'", reason="no shebang on Windows")
+def test_tox_testenv_interpret_shebang_skip_truncated(tmpdir):
+ testfile = tmpdir.join("check_shebang_truncation.py")
+ original_args = [str(testfile), "arg1", "arg2", "arg3"]
+
+ # interpreter (too long example)
+ testfile.write("#!" + ("x" * (MAXINTERP + 1)))
+ args = prepend_shebang_interpreter(original_args)
+
+ assert args == original_args
+
+
@pytest.mark.parametrize("download", [True, False, None])
def test_create_download(mocksession, newconfig, download):
config = newconfig(