Skip to content

Commit

Permalink
venv: do not prepend a truncated shebang interpreter (#2203)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdknight committed Sep 16, 2021
1 parent 3c1c29a commit 51cc218
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 5 deletions.
2 changes: 2 additions & 0 deletions docs/changelog/2208.bugfix.rst
@@ -0,0 +1,2 @@
Prevent tox from using a truncated interpreter when using
``TOX_LIMITED_SHEBANG`` -- by :user:`jdknight`.
4 changes: 2 additions & 2 deletions docs/config.rst
Expand Up @@ -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``::
Expand Down
10 changes: 7 additions & 3 deletions src/tox/venv.py
Expand Up @@ -19,6 +19,9 @@

from .config import DepConfig

#: maximum parsed shebang interpreter length (see: prepend_shebang_interpreter)
MAXINTERP = 2048


class CreationConfig:
def __init__(
Expand Down Expand Up @@ -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
Expand All @@ -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):
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test_venv.py
Expand Up @@ -9,6 +9,7 @@
from tox.interpreters import NoInterpreterInfo
from tox.session.commands.run.sequential import installpkg, runtestenv
from tox.venv import (
MAXINTERP,
CreationConfig,
VirtualEnv,
getdigest,
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit 51cc218

Please sign in to comment.