Skip to content

Commit 1ed25e3

Browse files
minrkblink1073
andauthored
Only prefer envs owned by the current user (#323)
Co-authored-by: Steven Silvester <[email protected]> closes #318
1 parent 719c1c3 commit 1ed25e3

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

jupyter_core/paths.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,49 @@ def get_home_dir() -> str:
6868
_dtemps: Dict[str, str] = {}
6969

7070

71+
def _do_i_own(path: str) -> bool:
72+
"""Return whether the current user owns the given path"""
73+
p = Path(path).resolve()
74+
75+
# walk up to first existing parent
76+
while not p.exists() and p != p.parent:
77+
p = p.parent
78+
79+
# simplest check: owner by name
80+
# not always implemented or available
81+
try:
82+
return p.owner() == os.getlogin()
83+
except (NotImplementedError, OSError):
84+
pass
85+
86+
if hasattr(os, 'geteuid'):
87+
try:
88+
st = p.stat()
89+
return st.st_uid == os.geteuid()
90+
except (NotImplementedError, OSError):
91+
# geteuid not always implemented
92+
pass
93+
94+
# no ownership checks worked, check write access
95+
return os.access(p, os.W_OK)
96+
97+
7198
def prefer_environment_over_user() -> bool:
7299
"""Determine if environment-level paths should take precedence over user-level paths."""
73100
# If JUPYTER_PREFER_ENV_PATH is defined, that signals user intent, so return its value
74101
if "JUPYTER_PREFER_ENV_PATH" in os.environ:
75102
return envset("JUPYTER_PREFER_ENV_PATH") # type:ignore[return-value]
76103

77104
# If we are in a Python virtualenv, default to True (see https://docs.python.org/3/library/venv.html#venv-def)
78-
if sys.prefix != sys.base_prefix:
105+
if sys.prefix != sys.base_prefix and _do_i_own(sys.prefix):
79106
return True
80107

81108
# If sys.prefix indicates Python comes from a conda/mamba environment that is not the root environment, default to True
82109
if (
83110
"CONDA_PREFIX" in os.environ
84111
and sys.prefix.startswith(os.environ["CONDA_PREFIX"])
85112
and os.environ.get("CONDA_DEFAULT_ENV", "base") != "base"
113+
and _do_i_own(sys.prefix)
86114
):
87115
return True
88116

jupyter_core/tests/test_paths.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,10 @@ def test_prefer_environment_over_user():
400400

401401
# Test default if environment variable is not set, and try to determine if we are in a virtual environment
402402
os.environ.pop("JUPYTER_PREFER_ENV_PATH", None)
403+
403404
# base prefix differs, venv
404405
with patch.object(sys, "base_prefix", "notthesame"):
405-
assert prefer_environment_over_user()
406+
assert prefer_environment_over_user() == paths._do_i_own(sys.prefix)
406407

407408
# conda
408409
with patch.object(sys, "base_prefix", sys.prefix):
@@ -411,7 +412,8 @@ def test_prefer_environment_over_user():
411412
assert not prefer_environment_over_user()
412413
# in non-base env, prefer it
413414
with patch.dict(os.environ, {"CONDA_PREFIX": sys.prefix, "CONDA_DEFAULT_ENV": "/tmp"}):
414-
assert prefer_environment_over_user()
415+
assert prefer_environment_over_user() == paths._do_i_own(sys.prefix)
416+
415417
# conda env defined, but we aren't using it
416418
with patch.dict(
417419
os.environ, {"CONDA_PREFIX": "/somewherelese", "CONDA_DEFAULT_ENV": "/tmp"}

0 commit comments

Comments
 (0)