From e8ecf261b69f86394ced5ef7d0fddc52d4c9a0a0 Mon Sep 17 00:00:00 2001 From: ATorrise Date: Fri, 7 Aug 2026 15:13:35 -0400 Subject: [PATCH 1/6] breaking! removes url loading from schema Signed-off-by: ATorrise --- CHANGELOG.md | 1 + src/core/zowe/core_for_zowe_sdk/config_file.py | 15 +++++---------- src/core/zowe/core_for_zowe_sdk/validators.py | 13 ++++++++++--- tests/unit/core/test_config.py | 15 ++++++++++++++- tests/unit/core/test_profile_manager.py | 13 +++++++++++++ 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d579cf23..387c4ce0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to the Zowe Client Python SDK will be documented in this fil ### Bug Fixes +- Removed support for loading a JSON schema from a remote `http(s)://` URL via the `$schema` config property. Local schema files are still supported. - Redacted request headers and restricted log directory/file to owner-only access. [#404](https://github.com/zowe/zowe-client-python-sdk/pull/404) - Fixed `Jobs.get_job_output_as_files` writing to a directory it never created, and made job output paths stay within the target directory. [#403](https://github.com/zowe/zowe-client-python-sdk/pull/403) - Updated the `pyo3` dependency of the Secrets SDK for technical currency. [#399](https://github.com/zowe/zowe-client-python-sdk/pull/399) diff --git a/src/core/zowe/core_for_zowe_sdk/config_file.py b/src/core/zowe/core_for_zowe_sdk/config_file.py index 82bc14d4..5d929c52 100644 --- a/src/core/zowe/core_for_zowe_sdk/config_file.py +++ b/src/core/zowe/core_for_zowe_sdk/config_file.py @@ -19,7 +19,6 @@ from typing import Any, NamedTuple, Optional, Union import json5 -import requests from .credential_manager import CredentialManager from .custom_warnings import ProfileNotFoundWarning, ProfileParsingWarning @@ -180,15 +179,11 @@ def schema_list(self, cwd: Optional[str] = None) -> list[dict[str, Any]]: schema_json: dict[str, Any] = {} if schema.startswith(("https://", "http://")): - try: - response = requests.get(schema) - response.raise_for_status() # Ensure it's a valid response - schema_json = response.json() - except requests.RequestException as e: - if not self.__suppress_config_file_warnings: - warnings.warn(f"Invalid schema request: {e}") - self.__logger.warning(f"Invalid schema request: {e}") - return [] + # remote schema loading is not supported + if not self.__suppress_config_file_warnings: + warnings.warn(f"Loading a JSON schema from a remote URL is not supported: {schema}") + self.__logger.warning(f"Loading a JSON schema from a remote URL is not supported: {schema}") + return [] elif schema.startswith("file://") or os.path.isfile(schema): try: diff --git a/src/core/zowe/core_for_zowe_sdk/validators.py b/src/core/zowe/core_for_zowe_sdk/validators.py index f340c75f..9a2b683c 100644 --- a/src/core/zowe/core_for_zowe_sdk/validators.py +++ b/src/core/zowe/core_for_zowe_sdk/validators.py @@ -14,7 +14,6 @@ from typing import Union, Any import json5 -import requests from jsonschema import validate @@ -30,10 +29,18 @@ def validate_config_json(path_config_json: Union[str, dict[str, Any]], path_sche Absolute path to zowe.schema.json cwd: str Path of the current working directory + + Raises + ------ + ValueError + When path_schema_json is a remote URL, which is not supported """ - # checks if the path_schema_json point to an internet URI and download the schema using the URI + # remote ($schema pointing to an http(s):// URL) schema loading is not supported; only local files may be used if path_schema_json.startswith("https://") or path_schema_json.startswith("http://"): - schema_json = requests.get(path_schema_json).json() + raise ValueError( + f"Loading a JSON schema from a remote URL is not supported: {path_schema_json}. " + "Use a local file path for the $schema property instead." + ) # checks if the path_schema_json is a file elif os.path.isfile(path_schema_json) or path_schema_json.startswith("file://"): diff --git a/tests/unit/core/test_config.py b/tests/unit/core/test_config.py index 2fe193df..b5878e6a 100644 --- a/tests/unit/core/test_config.py +++ b/tests/unit/core/test_config.py @@ -1,5 +1,6 @@ import importlib.util import os +from unittest import mock import json5 from jsonschema import ValidationError, validate @@ -136,6 +137,18 @@ def test_validate_config_json_with_block_comments(self): loaded_schema = json5.load(open(commented_schema_path, encoding="utf-8")) expected = validate(loaded_config, loaded_schema) - result = validate_config_json(commented_config_path, commented_schema_path, cwd=os.path.dirname(commented_config_path)) + result = validate_config_json( + commented_config_path, commented_schema_path, cwd=os.path.dirname(commented_config_path) + ) self.assertEqual(result, expected) + + def test_validate_config_json_rejects_remote_schema(self): + """Test validate_config_json rejects http(s):// schema URLs without making a network request.""" + with mock.patch("requests.get") as mock_get: + with self.assertRaises(ValueError): + validate_config_json(self.original_file_path, "https://example.com/zowe.schema.json", cwd=FIXTURES_PATH) + with self.assertRaises(ValueError): + validate_config_json(self.original_file_path, "http://example.com/zowe.schema.json", cwd=FIXTURES_PATH) + + mock_get.assert_not_called() diff --git a/tests/unit/core/test_profile_manager.py b/tests/unit/core/test_profile_manager.py index 1e797a43..ec98f7a9 100644 --- a/tests/unit/core/test_profile_manager.py +++ b/tests/unit/core/test_profile_manager.py @@ -296,6 +296,19 @@ def test_validate_schema_logger(self, get_pass_func, mock_logger_warning: mock.M config_file.validate_schema() self.assertEqual(mock_logger_warning.call_args[0][0], "Could not find $schema property") + def test_schema_list_rejects_remote_schema(self): + """Test that schema_list does not fetch a remote schema URL and returns an empty list instead.""" + with mock.patch("requests.get") as mock_get: + config_file = ConfigFile( + name="zowe_abcd", type="User Config", schema_property="https://example.com/zowe.schema.json" + ) + config_file.suppress_config_warnings(False) + with self.assertWarns(UserWarning): + result = config_file.schema_list() + + mock_get.assert_not_called() + self.assertEqual(result, []) + @mock.patch("zowe.secrets_for_zowe_sdk.keyring.get_password", side_effect=keyring_get_password_exception) def test_secure_props_loading_warning(self, get_pass_func): """ From c2df3dd73b7fd110bc08ddb2da8015da42901085 Mon Sep 17 00:00:00 2001 From: Amber Torrise <112635587+ATorrise@users.noreply.github.com> Date: Mon, 10 Aug 2026 07:51:33 -0400 Subject: [PATCH 2/6] breaking in changelog Signed-off-by: Amber Torrise <112635587+ATorrise@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 387c4ce0..695f3342 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to the Zowe Client Python SDK will be documented in this fil ### Bug Fixes -- Removed support for loading a JSON schema from a remote `http(s)://` URL via the `$schema` config property. Local schema files are still supported. +- **Breaking**: Removed support for loading a JSON schema from a remote `http(s)://` URL via the `$schema` config property. Local schema files are still supported. - Redacted request headers and restricted log directory/file to owner-only access. [#404](https://github.com/zowe/zowe-client-python-sdk/pull/404) - Fixed `Jobs.get_job_output_as_files` writing to a directory it never created, and made job output paths stay within the target directory. [#403](https://github.com/zowe/zowe-client-python-sdk/pull/403) - Updated the `pyo3` dependency of the Secrets SDK for technical currency. [#399](https://github.com/zowe/zowe-client-python-sdk/pull/399) From c145921f1e6e64210a0e7d30c50703f90c2fe487 Mon Sep 17 00:00:00 2001 From: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> Date: Mon, 10 Aug 2026 16:49:29 -0400 Subject: [PATCH 3/6] Update CHANGELOG.md Signed-off-by: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 695f3342..c69d9167 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to the Zowe Client Python SDK will be documented in this fil ### Bug Fixes -- **Breaking**: Removed support for loading a JSON schema from a remote `http(s)://` URL via the `$schema` config property. Local schema files are still supported. +- **Breaking**: Removed support for loading a JSON schema from a remote `http(s)://` URL via the `$schema` config property. Local schema files are still supported. [#412](https://github.com/zowe/zowe-client-python-sdk/pull/412) - Redacted request headers and restricted log directory/file to owner-only access. [#404](https://github.com/zowe/zowe-client-python-sdk/pull/404) - Fixed `Jobs.get_job_output_as_files` writing to a directory it never created, and made job output paths stay within the target directory. [#403](https://github.com/zowe/zowe-client-python-sdk/pull/403) - Updated the `pyo3` dependency of the Secrets SDK for technical currency. [#399](https://github.com/zowe/zowe-client-python-sdk/pull/399) From 2822a86f1912423e2e80d2bae146491f0e524cac Mon Sep 17 00:00:00 2001 From: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> Date: Mon, 24 Aug 2026 16:09:33 -0400 Subject: [PATCH 4/6] chore: reuse string Signed-off-by: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> --- src/core/zowe/core_for_zowe_sdk/config_file.py | 6 +++--- src/core/zowe/core_for_zowe_sdk/validators.py | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/core/zowe/core_for_zowe_sdk/config_file.py b/src/core/zowe/core_for_zowe_sdk/config_file.py index 5d929c52..8def253d 100644 --- a/src/core/zowe/core_for_zowe_sdk/config_file.py +++ b/src/core/zowe/core_for_zowe_sdk/config_file.py @@ -25,7 +25,7 @@ from .exceptions import ProfileNotFound from .logger import Log from .profile_constants import GLOBAL_CONFIG_NAME, TEAM_CONFIG, USER_CONFIG -from .validators import validate_config_json +from .validators import REMOTE_SCHEMA_UNSUPPORTED, validate_config_json HOME = os.path.expanduser("~") GLOBAL_CONFIG_LOCATION = os.path.join(HOME, ".zowe") @@ -181,8 +181,8 @@ def schema_list(self, cwd: Optional[str] = None) -> list[dict[str, Any]]: if schema.startswith(("https://", "http://")): # remote schema loading is not supported if not self.__suppress_config_file_warnings: - warnings.warn(f"Loading a JSON schema from a remote URL is not supported: {schema}") - self.__logger.warning(f"Loading a JSON schema from a remote URL is not supported: {schema}") + warnings.warn(f"{REMOTE_SCHEMA_UNSUPPORTED}: {schema}") + self.__logger.warning(f"{REMOTE_SCHEMA_UNSUPPORTED}: {schema}") return [] elif schema.startswith("file://") or os.path.isfile(schema): diff --git a/src/core/zowe/core_for_zowe_sdk/validators.py b/src/core/zowe/core_for_zowe_sdk/validators.py index 9a2b683c..8d1b8276 100644 --- a/src/core/zowe/core_for_zowe_sdk/validators.py +++ b/src/core/zowe/core_for_zowe_sdk/validators.py @@ -11,11 +11,13 @@ """ import os -from typing import Union, Any +from typing import Any, Union import json5 from jsonschema import validate +REMOTE_SCHEMA_UNSUPPORTED = "Loading a JSON schema from a remote URL is not supported" + def validate_config_json(path_config_json: Union[str, dict[str, Any]], path_schema_json: str, cwd: str) -> None: """ @@ -38,7 +40,7 @@ def validate_config_json(path_config_json: Union[str, dict[str, Any]], path_sche # remote ($schema pointing to an http(s):// URL) schema loading is not supported; only local files may be used if path_schema_json.startswith("https://") or path_schema_json.startswith("http://"): raise ValueError( - f"Loading a JSON schema from a remote URL is not supported: {path_schema_json}. " + f"{REMOTE_SCHEMA_UNSUPPORTED}: {path_schema_json}. " "Use a local file path for the $schema property instead." ) From 952871af8b12f50b886ce10fe13b46626d575376 Mon Sep 17 00:00:00 2001 From: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> Date: Mon, 24 Aug 2026 16:13:01 -0400 Subject: [PATCH 5/6] raise the error instead Signed-off-by: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> --- src/core/zowe/core_for_zowe_sdk/config_file.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/zowe/core_for_zowe_sdk/config_file.py b/src/core/zowe/core_for_zowe_sdk/config_file.py index 8def253d..6f82a263 100644 --- a/src/core/zowe/core_for_zowe_sdk/config_file.py +++ b/src/core/zowe/core_for_zowe_sdk/config_file.py @@ -169,6 +169,11 @@ def schema_list(self, cwd: Optional[str] = None) -> list[dict[str, Any]]: ------- list[dict[str, Any]] properties from schema + + Raises + ------ + ValueError + When the $schema property points to a remote URL, which is not supported """ schema: Optional[Union[str, dict[str, Any]]] = self.schema_property @@ -180,10 +185,7 @@ def schema_list(self, cwd: Optional[str] = None) -> list[dict[str, Any]]: if schema.startswith(("https://", "http://")): # remote schema loading is not supported - if not self.__suppress_config_file_warnings: - warnings.warn(f"{REMOTE_SCHEMA_UNSUPPORTED}: {schema}") - self.__logger.warning(f"{REMOTE_SCHEMA_UNSUPPORTED}: {schema}") - return [] + raise ValueError(f"{REMOTE_SCHEMA_UNSUPPORTED}: {schema}") elif schema.startswith("file://") or os.path.isfile(schema): try: From fbfccf797cdfc714bb85384ea5dd6df4ba98dbd0 Mon Sep 17 00:00:00 2001 From: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:06:59 -0400 Subject: [PATCH 6/6] review: fix tests Signed-off-by: Fernando Rijo Cedeno <37381190+zFernand0@users.noreply.github.com> --- tests/unit/core/test_profile_manager.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/core/test_profile_manager.py b/tests/unit/core/test_profile_manager.py index ec98f7a9..ad944689 100644 --- a/tests/unit/core/test_profile_manager.py +++ b/tests/unit/core/test_profile_manager.py @@ -297,17 +297,16 @@ def test_validate_schema_logger(self, get_pass_func, mock_logger_warning: mock.M self.assertEqual(mock_logger_warning.call_args[0][0], "Could not find $schema property") def test_schema_list_rejects_remote_schema(self): - """Test that schema_list does not fetch a remote schema URL and returns an empty list instead.""" + """Test that schema_list does not fetch a remote schema URL and raises an error instead.""" with mock.patch("requests.get") as mock_get: config_file = ConfigFile( name="zowe_abcd", type="User Config", schema_property="https://example.com/zowe.schema.json" ) config_file.suppress_config_warnings(False) - with self.assertWarns(UserWarning): - result = config_file.schema_list() + with self.assertRaises(ValueError): + config_file.schema_list() mock_get.assert_not_called() - self.assertEqual(result, []) @mock.patch("zowe.secrets_for_zowe_sdk.keyring.get_password", side_effect=keyring_get_password_exception) def test_secure_props_loading_warning(self, get_pass_func):