From 2884545dbe42a6e8208be2f6711412ecabd53525 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah <22363102+codeforester@users.noreply.github.com> Date: Thu, 8 Oct 2026 10:58:14 +0530 Subject: [PATCH 1/2] fix: isolate aliased configuration mappings --- lib/python/base_cli/config.py | 14 +++++++++++++- tests/test_batteries_included_config.py | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/python/base_cli/config.py b/lib/python/base_cli/config.py index 2b9519a..25953e5 100644 --- a/lib/python/base_cli/config.py +++ b/lib/python/base_cli/config.py @@ -176,10 +176,22 @@ def _merge_mapping_validated( for existing_path in tuple(provenance): if existing_path == path or existing_path.startswith(f"{path}."): del provenance[existing_path] - target[key] = dict(value) if isinstance(value, Mapping) else value + target[key] = _copy_config_value(value) provenance.update(_leaf_provenance(value, source, path)) +def _copy_config_value(value: Any) -> Any: + """Copy nested configuration containers without preserving YAML aliases.""" + + if isinstance(value, Mapping): + return {key: _copy_config_value(child) for key, child in value.items()} + if isinstance(value, list): + return [_copy_config_value(child) for child in value] + if isinstance(value, tuple): + return tuple(_copy_config_value(child) for child in value) + return value + + class BatteriesIncludedConfigLoader: """Load conventional user, project, environment, and explicit layers. diff --git a/tests/test_batteries_included_config.py b/tests/test_batteries_included_config.py index f65f03f..f7682e4 100644 --- a/tests/test_batteries_included_config.py +++ b/tests/test_batteries_included_config.py @@ -61,8 +61,25 @@ def test_shared_mapping_alias_is_valid_but_recursive_alias_is_rejected_with_path provenance: dict[str, str] = {} _merge_mapping(values, provenance, valid, "user") self.assertEqual(values, {"left": shared, "right": shared}) + self.assertIsNot(values["left"], shared) + self.assertIsNot(values["left"], values["right"]) + assert isinstance(values["left"], dict) + values["left"]["answer"] = 7 + self.assertEqual(values["right"], {"answer": 42}) self.assertEqual(provenance, {"left.answer": "user", "right.answer": "user"}) + def test_nested_mapping_aliases_are_isolated_across_layers(self) -> None: + shared = {"limits": {"retries": 2}} + values: dict[str, object] = {} + provenance: dict[str, str] = {} + + _merge_mapping(values, provenance, {"first": shared, "second": shared}, "user") + _merge_mapping(values, provenance, {"first": {"limits": {"timeout": 30}}}, "project") + + self.assertEqual(values["first"], {"limits": {"retries": 2, "timeout": 30}}) + self.assertEqual(values["second"], {"limits": {"retries": 2}}) + self.assertEqual(shared, {"limits": {"retries": 2}}) + with tempfile.TemporaryDirectory() as tmpdir: path = Path(tmpdir) / "recursive.yaml" _write_yaml(path, "nested: &node\n child: *node\n") From 141c5dab659fdde2027c65a569e483520e575d14 Mon Sep 17 00:00:00 2001 From: Ramesh Padmanabhaiah <22363102+codeforester@users.noreply.github.com> Date: Thu, 8 Oct 2026 22:32:29 +0530 Subject: [PATCH 2/2] test: keep recursive alias assertion with its test --- tests/test_batteries_included_config.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_batteries_included_config.py b/tests/test_batteries_included_config.py index f7682e4..7880547 100644 --- a/tests/test_batteries_included_config.py +++ b/tests/test_batteries_included_config.py @@ -68,6 +68,12 @@ def test_shared_mapping_alias_is_valid_but_recursive_alias_is_rejected_with_path self.assertEqual(values["right"], {"answer": 42}) self.assertEqual(provenance, {"left.answer": "user", "right.answer": "user"}) + with tempfile.TemporaryDirectory() as tmpdir: + path = Path(tmpdir) / "recursive.yaml" + _write_yaml(path, "nested: &node\n child: *node\n") + with self.assertRaisesRegex(base_cli.ConfigurationError, "recursive.yaml.*recursive value.*nested.child"): + BatteriesIncludedConfigLoader(user_config_dir=Path(tmpdir) / "user").load(None, path) + def test_nested_mapping_aliases_are_isolated_across_layers(self) -> None: shared = {"limits": {"retries": 2}} values: dict[str, object] = {} @@ -80,12 +86,6 @@ def test_nested_mapping_aliases_are_isolated_across_layers(self) -> None: self.assertEqual(values["second"], {"limits": {"retries": 2}}) self.assertEqual(shared, {"limits": {"retries": 2}}) - with tempfile.TemporaryDirectory() as tmpdir: - path = Path(tmpdir) / "recursive.yaml" - _write_yaml(path, "nested: &node\n child: *node\n") - with self.assertRaisesRegex(base_cli.ConfigurationError, "recursive.yaml.*recursive value.*nested.child"): - BatteriesIncludedConfigLoader(user_config_dir=Path(tmpdir) / "user").load(None, path) - def test_mapping_depth_is_bounded_before_recursive_merge_or_provenance(self) -> None: nested: dict[str, object] = {"value": 1} for index in range(65):