diff --git a/jupyter_server/serverapp.py b/jupyter_server/serverapp.py index bf375cbef6..f257d11498 100644 --- a/jupyter_server/serverapp.py +++ b/jupyter_server/serverapp.py @@ -1427,6 +1427,12 @@ def _default_allow_remote(self) -> bool: """, ) + allow_insecure_kernelspec_params = Bool( + False, + config=True, + help="""Allow to use insecure kernelspec parameters""", + ) + browser = Unicode( "", config=True, @@ -2180,6 +2186,7 @@ def init_event_logger(self) -> None: self.event_logger.register_event_schema(schema_path) def init_webapp(self) -> None: + # """initialize tornado webapp""" self.tornado_settings["allow_origin"] = self.allow_origin self.tornado_settings["websocket_compression_options"] = self.websocket_compression_options @@ -2991,7 +2998,6 @@ def target(): def start_app(self) -> None: """Start the Jupyter Server application.""" super().start() - if not self.allow_root: # check if we are running as root, and abort if it's not allowed try: @@ -3030,6 +3036,10 @@ def start_app(self) -> None: # Handle the browser opening. if self.open_browser and not self.sock: self.launch_browser() + if self.allow_insecure_kernelspec_params: + self.kernel_spec_manager.allow_insecure_kernelspec_params( + self.allow_insecure_kernelspec_params + ) if self.identity_provider.token and self.identity_provider.token_generated: # log full URL with generated token, so there's a copy/pasteable link diff --git a/jupyter_server/services/sessions/handlers.py b/jupyter_server/services/sessions/handlers.py index 3e013c0335..0e9181f41a 100644 --- a/jupyter_server/services/sessions/handlers.py +++ b/jupyter_server/services/sessions/handlers.py @@ -77,6 +77,7 @@ async def post(self): kernel = model.get("kernel", {}) kernel_name = kernel.get("name", None) kernel_id = kernel.get("id", None) + custom_kernel_specs = kernel.get("custom_kernel_specs", {}) if not kernel_id and not kernel_name: self.log.debug("No kernel specified, using default kernel") @@ -93,6 +94,7 @@ async def post(self): kernel_id=kernel_id, name=name, type=mtype, + custom_kernel_specs=custom_kernel_specs, ) except NoSuchKernel: msg = ( @@ -152,6 +154,9 @@ async def patch(self, session_id): changes["name"] = model["name"] if "type" in model: changes["type"] = model["type"] + if "custom_kernel_specs" in model: + changes["custom_kernel_specs"] = model["custom_kernel_specs"] + if "kernel" in model: # Kernel id takes precedence over name. if model["kernel"].get("id") is not None: @@ -160,6 +165,10 @@ async def patch(self, session_id): raise web.HTTPError(400, "No such kernel: %s" % kernel_id) changes["kernel_id"] = kernel_id elif model["kernel"].get("name") is not None: + if "custom_kernel_specs" in model["kernel"]: + custom_kernel_specs = model["kernel"]["custom_kernel_specs"] + else: + custom_kernel_specs = None kernel_name = model["kernel"]["name"] kernel_id = await sm.start_kernel_for_session( session_id, @@ -167,6 +176,7 @@ async def patch(self, session_id): name=before["name"], path=before["path"], type=before["type"], + custom_kernel_specs=custom_kernel_specs, ) changes["kernel_id"] = kernel_id diff --git a/jupyter_server/services/sessions/sessionmanager.py b/jupyter_server/services/sessions/sessionmanager.py index 8b392b4e1b..db889c942b 100644 --- a/jupyter_server/services/sessions/sessionmanager.py +++ b/jupyter_server/services/sessions/sessionmanager.py @@ -267,6 +267,7 @@ async def create_session( type: Optional[str] = None, kernel_name: Optional[KernelName] = None, kernel_id: Optional[str] = None, + custom_kernel_specs: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: """Creates a session and returns its model @@ -283,7 +284,7 @@ async def create_session( pass else: kernel_id = await self.start_kernel_for_session( - session_id, path, name, type, kernel_name + session_id, path, name, type, kernel_name, custom_kernel_specs ) record.kernel_id = kernel_id self._pending_sessions.update(record) @@ -319,6 +320,7 @@ async def start_kernel_for_session( name: Optional[ModelName], type: Optional[str], kernel_name: Optional[KernelName], + custom_kernel_specs: Optional[Dict[str, Any]] = None, ) -> str: """Start a new kernel for a given session. @@ -335,6 +337,8 @@ async def start_kernel_for_session( the type of the session kernel_name : str the name of the kernel specification to use. The default kernel name will be used if not provided. + custom_kernel_specs: dict + dictionary of kernel custom specifications """ # allow contents manager to specify kernels cwd kernel_path = await ensure_async(self.contents_manager.get_kernel_path(path=path)) @@ -344,6 +348,7 @@ async def start_kernel_for_session( path=kernel_path, kernel_name=kernel_name, env=kernel_env, + custom_kernel_specs=custom_kernel_specs, ) return cast(str, kernel_id)