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 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")
+25
View File
@@ -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]] = []