From 4ab02025c71df9c8912ba359efe939c32e7ee3b5 Mon Sep 17 00:00:00 2001 From: nac Date: Mon, 13 Jul 2026 01:40:17 +0000 Subject: [PATCH] fix: reject nested project write values --- nocobase_crm_mcp/nb_client.py | 15 +++++++++++---- tests/test_nb_client.py | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/nocobase_crm_mcp/nb_client.py b/nocobase_crm_mcp/nb_client.py index 17b827a..5eaf694 100644 --- a/nocobase_crm_mcp/nb_client.py +++ b/nocobase_crm_mcp/nb_client.py @@ -3,6 +3,7 @@ from __future__ import annotations import json import os import subprocess +from collections.abc import Set as AbstractSet from pathlib import Path from typing import Any, Callable, Mapping, Sequence @@ -95,8 +96,7 @@ class NbClient: values: Mapping[str, Any], whitelist: Sequence[str], ) -> dict[str, Any]: - if not values: - raise ValueError("values must not be empty") + self._validate_scalar_values(values) command = self._resource_command("create", resource) self._append_json(command, "--values", values) self._append_repeated(command, "--whitelist", whitelist) @@ -109,8 +109,7 @@ class NbClient: values: Mapping[str, Any], whitelist: Sequence[str], ) -> dict[str, Any]: - if not values: - raise ValueError("values must not be empty") + self._validate_scalar_values(values) command = self._resource_command("update", resource) self._append_json_or_scalar(command, "--filter-by-tk", record_id) self._append_json(command, "--values", values) @@ -301,3 +300,11 @@ class NbClient: if value is None or value == "": return command.extend([flag, str(value)]) + + @staticmethod + def _validate_scalar_values(values: Mapping[str, Any]) -> None: + if not values: + raise ValueError("values must not be empty") + for field, value in values.items(): + if isinstance(value, (Mapping, list, AbstractSet, tuple)): + raise ValueError(f"values[{field!r}] must be scalar") diff --git a/tests/test_nb_client.py b/tests/test_nb_client.py index f0245a0..d274be0 100644 --- a/tests/test_nb_client.py +++ b/tests/test_nb_client.py @@ -132,6 +132,31 @@ class NbClientTests(unittest.TestCase): self.assertEqual(commands, []) + def test_record_writes_reject_nested_values_without_running_command(self) -> None: + commands: list[list[str]] = [] + + def runner(cmd, **kwargs): + commands.append(cmd) + return subprocess.CompletedProcess(cmd, 0, stdout='{"data":{}}', stderr="") + + client = NbClient(env_name="nb-mcp", runner=runner) + nested_values = [ + {"client": {"id": 3}}, + {"client_ids": [3]}, + {"client_ids": {3}}, + {"client_ids": (3,)}, + ] + + for values in nested_values: + with self.subTest(operation="create", values=values): + with self.assertRaises(ValueError): + client.create_record("t_projects", values, list(values)) + with self.subTest(operation="update", values=values): + with self.assertRaises(ValueError): + client.update_record("t_projects", 7, values, list(values)) + + self.assertEqual(commands, []) + def test_list_collection_fields_uses_data_modeling_command(self) -> None: commands: list[list[str]] = []