Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,3 @@ def enterprise_config(pytestconfig):
return core.HttpConfiguration(uri, api_key)
else:
pytest.skip("--enterprise-uri or --enterprise-api-key setting not found")


@pytest.fixture(scope="session", autouse=True)
def pydantic_forbid_extra_fields():
"""Fixture to disable allowing extra fields in our Pydantic models."""
JsonModel.Config.extra = Extra.forbid
28 changes: 26 additions & 2 deletions nisystemlink/clients/core/_jupyter_http_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
"""Implementation of JupyterHttpConfiguration."""

import os
import sys

from nisystemlink.clients import core
from nisystemlink.clients.core._internal._path_constants import PathConstants


class JupyterHttpConfiguration(core.HttpConfiguration):
Expand All @@ -20,6 +22,28 @@ def __init__(self) -> None:
Raises:
KeyError: if the expected environment variables are not set.
"""
super().__init__(
os.environ[self._HTTP_URI_ENV_VAR], os.environ[self._HTTP_API_KEY_ENV_VAR]
http_uri = os.environ[self._HTTP_URI_ENV_VAR]
api_key = os.environ[self._HTTP_API_KEY_ENV_VAR]
systemlink_server_cert_path = (
PathConstants.application_data_directory
/ "Certificates"
/ "http-server"
/ "http-server.cer"
)

# SystemLink Server 26Q3 restricts notebook executions (by default). Access to the `HttpConfigurations` folder
# is no longer granted for notebooks running under the JupyterHub/NotebookExecution services. Since config
# files under `HttpConfigurations` are no longer readable, creating client objects from this library, from SLS
# notebooks, will default to using this `JupyterHttpConfiguration`. However, this does not set a `cert_path`,
# so HTTPS requests will fail.
# When running SystemLink Server notebooks (Windows), we will therefore pass the Web Server CA certificate's
# path as the `cert_path`, if the file exists. This will allow clients created with the default configuration
# to use this CA certificate.
# If the file does not exist (when the Web Server is configured in HTTP mode), do not pass it; an invalid
# `cert_path` will lead to errors.
if sys.platform.startswith("win") and os.path.exists(
systemlink_server_cert_path
):
super().__init__(http_uri, api_key, cert_path=systemlink_server_cert_path)
else:
super().__init__(http_uri, api_key)
110 changes: 110 additions & 0 deletions tests/core/test_jupyter_http_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import os
import pathlib
from unittest.mock import patch

from nisystemlink.clients.core import JupyterHttpConfiguration


_HTTP_URI_ENV_VAR = "SYSTEMLINK_HTTP_URI"
_HTTP_API_KEY_ENV_VAR = "SYSTEMLINK_API_KEY"
_SYSTEMLINK_SERVER_CERT_PATH = (
pathlib.Path(r"C:\ProgramData\National Instruments\Skyline")
/ "Certificates"
/ "http-server"
/ "http-server.cer"
)
_SYSTEMLINK_API_KEY_HEADER = "x-ni-api-key"


class TestJupyterHttpConfiguration:
# Patch PathConstants._application_data_directory so that we have the proper Windows path
# when running the tests on Linux.
@patch(
"nisystemlink.clients.core._internal._path_constants.PathConstants._application_data_directory",
pathlib.Path(r"C:\ProgramData\National Instruments\Skyline"),
)
def test__cert_file_exists_on_windows__cert_path_is_passed(self):
def mock_exists(path):
if path == _SYSTEMLINK_SERVER_CERT_PATH:
return True
return False

with patch("sys.platform", "win32"):
with patch("os.path.exists", side_effect=mock_exists):
with patch.dict(
os.environ,
{
_HTTP_URI_ENV_VAR: "https://my-uri",
_HTTP_API_KEY_ENV_VAR: "my-api-key",
},
):
config = JupyterHttpConfiguration()
assert config.server_uri == "https://my-uri"
assert config.api_keys[_SYSTEMLINK_API_KEY_HEADER] == "my-api-key"
assert config.cert_path == _SYSTEMLINK_SERVER_CERT_PATH

# Patch PathConstants._application_data_directory so that we have the proper Windows path
# when running the tests on Linux.
@patch(
"nisystemlink.clients.core._internal._path_constants.PathConstants._application_data_directory",
pathlib.Path(r"C:\ProgramData\National Instruments\Skyline"),
)
def test__cert_file_does_not_exist_on_windows__cert_path_is_not_passed(self):
def mock_exists(path):
if path == _SYSTEMLINK_SERVER_CERT_PATH:
return False
return True

with patch("sys.platform", "win32"):
with patch("os.path.exists", side_effect=mock_exists):
with patch.dict(
os.environ,
{
_HTTP_URI_ENV_VAR: "https://my-uri",
_HTTP_API_KEY_ENV_VAR: "my-api-key",
},
):
config = JupyterHttpConfiguration()
assert config.server_uri == "https://my-uri"
assert config.api_keys[_SYSTEMLINK_API_KEY_HEADER] == "my-api-key"
assert config.cert_path is None

def test__cert_file_exists_on_linux__cert_path_is_not_passed(self):
def mock_exists(path):
if path == _SYSTEMLINK_SERVER_CERT_PATH:
return True
return False

with patch("sys.platform", "linux"):
with patch("os.path.exists", side_effect=mock_exists):
with patch.dict(
os.environ,
{
_HTTP_URI_ENV_VAR: "https://my-uri",
_HTTP_API_KEY_ENV_VAR: "my-api-key",
},
):
config = JupyterHttpConfiguration()
assert config.server_uri == "https://my-uri"
assert config.api_keys[_SYSTEMLINK_API_KEY_HEADER] == "my-api-key"
assert config.cert_path is None

def test__cert_file_does_not_exist_on_linux__cert_path_is_not_passed(self):
def mock_exists(path):
if path == _SYSTEMLINK_SERVER_CERT_PATH:
return False
return True

with patch("sys.platform", "linux"):
with patch("os.path.exists", side_effect=mock_exists):
with patch.dict(
os.environ,
{
_HTTP_URI_ENV_VAR: "https://my-uri",
_HTTP_API_KEY_ENV_VAR: "my-api-key",
},
):
config = JupyterHttpConfiguration()
assert config.server_uri == "https://my-uri"
assert config.api_keys[_SYSTEMLINK_API_KEY_HEADER] == "my-api-key"
assert config.cert_path is None
Loading