Skip to content

Commit 72844bf

Browse files
committed
Path resolution by kernel manager and providers
1 parent 396e665 commit 72844bf

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

jupyter_client/manager.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ def client(self, **kwargs: t.Any) -> BlockingKernelClient:
279279
# Kernel management
280280
# --------------------------------------------------------------------------
281281

282+
def resolve_path(self, path: str) -> t.Optional[str]:
283+
"""Resolve path to given file."""
284+
assert self.provisioner is not None
285+
print('kernel manager resolving path!', path, 'to', self.provisioner.resolve_path(path))
286+
return self.provisioner.resolve_path(path)
287+
282288
def update_env(self, *, env: t.Dict[str, str]) -> None:
283289
"""
284290
Allow to update the environment of a kernel manager.

jupyter_client/provisioning/local_provisioner.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Distributed under the terms of the Modified BSD License.
44
import asyncio
55
import os
6+
import pathlib
67
import signal
78
import sys
89
from typing import TYPE_CHECKING, Any, Dict, List, Optional
@@ -31,6 +32,7 @@ class LocalProvisioner(KernelProvisionerBase): # type:ignore[misc]
3132
pgid = None
3233
ip = None
3334
ports_cached = False
35+
cwd = None
3436

3537
@property
3638
def has_process(self) -> bool:
@@ -217,8 +219,18 @@ async def launch_kernel(self, cmd: List[str], **kwargs: Any) -> KernelConnection
217219

218220
self.pid = self.process.pid
219221
self.pgid = pgid
222+
self.cwd = kwargs.get('cwd', pathlib.Path.cwd())
220223
return self.connection_info
221224

225+
async def resolve_path(self, path_str: str) -> Optional[str]:
226+
"""Resolve path to given file."""
227+
path = pathlib.Path(path_str).expanduser()
228+
if path.is_absolute():
229+
return path.as_posix()
230+
if self.cwd:
231+
return (pathlib.Path(self.cwd) / path).resolve().as_posix()
232+
return None
233+
222234
@staticmethod
223235
def _scrub_kwargs(kwargs: Dict[str, Any]) -> Dict[str, Any]:
224236
"""Remove any keyword arguments that Popen does not tolerate."""

jupyter_client/provisioning/provisioner_base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,21 @@ def get_stable_start_time(self, recommended: float = 10.0) -> float:
219219
"""
220220
return recommended
221221

222+
def resolve_path(self, path: str) -> Optional[str]:
223+
"""
224+
Returns the path resolved relative to kernel working directory.
225+
226+
For example, path `my_code.py` for a kernel started in `/tmp/`
227+
should result in `/tmp/my_code.py`, while path `~/test.py` for
228+
a kernel started in `/home/my_user/` should resolve to the
229+
(fully specified) `/home/my_user/test.py` path.
230+
231+
The provisioner may choose not to resolve any paths, or restrict
232+
the resolution to paths local to the kernel working directory
233+
to prevent path traversal and exposure of file system layout.
234+
"""
235+
return None
236+
222237
def _finalize_env(self, env: Dict[str, str]) -> None:
223238
"""
224239
Ensures env is appropriate prior to launch.

0 commit comments

Comments
 (0)