diff --git a/jedi/api/environment.py b/jedi/api/environment.py index 1c1f4f2e..51b9eee8 100644 --- a/jedi/api/environment.py +++ b/jedi/api/environment.py @@ -16,6 +16,7 @@ import parso _VersionInfo = namedtuple('VersionInfo', 'major minor micro') _SUPPORTED_PYTHONS = ['3.6', '3.5', '3.4', '3.3', '2.7'] +_SAFE_PATHS = ['/usr/bin', '/usr/local/bin'] class InvalidPythonEnvironment(Exception): @@ -308,23 +309,23 @@ def _is_safe(executable_path): if environment.executable == executable_path: return True return False - else: - if _is_unix_admin(): - # In case we are root, just be conservative and - # only execute known paths. - return any(real_path.startswith(p) for p in '/usr/bin') - uid = os.stat(real_path).st_uid - # The interpreter needs to be owned by root. This means that it wasn't - # written by a user and therefore attacking Jedi is not as simple. - # The attack could look like the following: - # 1. A user clones a repository. - # 2. The repository has an inocent looking folder called foobar. jedi - # searches for the folder and executes foobar/bin/python --version if - # there's also a foobar/bin/activate. - # 3. The bin/python is obviously not a python script but a bash script or - # whatever the attacker wants. - return uid == 0 + if _is_unix_admin(): + # In case we are root, just be conservative and + # only execute known paths. + return any(real_path.startswith(p) for p in _SAFE_PATHS) + + uid = os.stat(real_path).st_uid + # The interpreter needs to be owned by root. This means that it wasn't + # written by a user and therefore attacking Jedi is not as simple. + # The attack could look like the following: + # 1. A user clones a repository. + # 2. The repository has an inocent looking folder called foobar. jedi + # searches for the folder and executes foobar/bin/python --version if + # there's also a foobar/bin/activate. + # 3. The bin/python is obviously not a python script but a bash script or + # whatever the attacker wants. + return uid == 0 def _is_unix_admin(): diff --git a/test/conftest.py b/test/conftest.py index 59f423b3..0a5598e3 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -138,7 +138,7 @@ def venv_path(tmpdir, environment): # ones. Instead, we find the real Python executable by printing the value # of sys.base_prefix or sys.real_prefix if we are in a virtualenv. output = subprocess.check_output([ - environment._executable, "-c", + environment.executable, "-c", "import sys; " "print(sys.real_prefix if hasattr(sys, 'real_prefix') else sys.base_prefix)" ]) @@ -146,7 +146,7 @@ def venv_path(tmpdir, environment): if os.name == 'nt': executable_path = os.path.join(prefix, 'python') else: - executable_name = os.path.basename(environment._executable) + executable_name = os.path.basename(environment.executable) executable_path = os.path.join(prefix, 'bin', executable_name) subprocess.call([executable_path, '-m', 'venv', dirname]) diff --git a/test/test_api/test_environment.py b/test/test_api/test_environment.py index f8209ce7..3d81d835 100644 --- a/test/test_api/test_environment.py +++ b/test/test_api/test_environment.py @@ -100,14 +100,14 @@ def test_not_existing_virtualenv(): """Should not match the path that was given""" path = '/foo/bar/jedi_baz' with set_environment_variable('VIRTUAL_ENV', path): - assert get_default_environment()._executable != path + assert get_default_environment().executable != path def test_working_venv(venv_path): with set_environment_variable('VIRTUAL_ENV', venv_path): - assert get_default_environment()._base_path == venv_path + assert get_default_environment().path == venv_path def test_scanning_venvs(venv_path): parent_dir = os.path.dirname(venv_path) - assert any(venv._base_path == venv_path for venv in find_virtualenvs([parent_dir])) + assert any(venv.path == venv_path for venv in find_virtualenvs([parent_dir])) diff --git a/test/test_evaluate/test_sys_path.py b/test/test_evaluate/test_sys_path.py index 51deea21..776f8d04 100644 --- a/test/test_evaluate/test_sys_path.py +++ b/test/test_evaluate/test_sys_path.py @@ -4,7 +4,7 @@ import sys import shutil from jedi.evaluate import sys_path -from jedi.api.environment import Environment +from jedi.api.environment import create_environment def test_paths_from_assignment(Script): @@ -29,11 +29,10 @@ def test_paths_from_assignment(Script): def test_venv_and_pths(venv_path): pjoin = os.path.join - bin_name = 'Scripts' if os.name == 'nt' else 'bin' - virtualenv = Environment(venv_path, pjoin(venv_path, bin_name, 'python')) + virtualenv = create_environment(venv_path) CUR_DIR = os.path.dirname(__file__) - site_pkg_path = pjoin(virtualenv._base_path, 'lib') + site_pkg_path = pjoin(virtualenv.path, 'lib') if os.name == 'nt': site_pkg_path = pjoin(site_pkg_path, 'site-packages') else: