fix: reject nested project write values

This commit is contained in:
nac
2026-07-13 01:40:17 +00:00
parent e213a91fea
commit 4ab02025c7
2 changed files with 36 additions and 4 deletions
+11 -4
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import json import json
import os import os
import subprocess import subprocess
from collections.abc import Set as AbstractSet
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Mapping, Sequence from typing import Any, Callable, Mapping, Sequence
@@ -95,8 +96,7 @@ class NbClient:
values: Mapping[str, Any], values: Mapping[str, Any],
whitelist: Sequence[str], whitelist: Sequence[str],
) -> dict[str, Any]: ) -> dict[str, Any]:
if not values: self._validate_scalar_values(values)
raise ValueError("values must not be empty")
command = self._resource_command("create", resource) command = self._resource_command("create", resource)
self._append_json(command, "--values", values) self._append_json(command, "--values", values)
self._append_repeated(command, "--whitelist", whitelist) self._append_repeated(command, "--whitelist", whitelist)
@@ -109,8 +109,7 @@ class NbClient:
values: Mapping[str, Any], values: Mapping[str, Any],
whitelist: Sequence[str], whitelist: Sequence[str],
) -> dict[str, Any]: ) -> dict[str, Any]:
if not values: self._validate_scalar_values(values)
raise ValueError("values must not be empty")
command = self._resource_command("update", resource) command = self._resource_command("update", resource)
self._append_json_or_scalar(command, "--filter-by-tk", record_id) self._append_json_or_scalar(command, "--filter-by-tk", record_id)
self._append_json(command, "--values", values) self._append_json(command, "--values", values)
@@ -301,3 +300,11 @@ class NbClient:
if value is None or value == "": if value is None or value == "":
return return
command.extend([flag, str(value)]) 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")
+25
View File
@@ -132,6 +132,31 @@ class NbClientTests(unittest.TestCase):
self.assertEqual(commands, []) 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: def test_list_collection_fields_uses_data_modeling_command(self) -> None:
commands: list[list[str]] = [] commands: list[list[str]] = []