Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ dependencies = [
"pydantic-settings>=2.10.1",
"psutil>=7.0.0",
"scipy>=1.16.1",
"simpleeval>=1.0.3",
"simpleeval>=1.0.5",
"pandera>=0.26.1",
"fastapi>=0.117.1",
"uvicorn>=0.36.0",
"fastmcp>=2.12.4",
"fastmcp>=3.2.0",
"smithery>=0.4.2",
]

Expand Down Expand Up @@ -373,9 +373,10 @@ dev = [
"mkdocstrings[python]>=0.30.0",
"mypy>=1.17.1",
"pandas-stubs>=2.3.0",
"pipdeptree>=2.35.2",
"pre-commit>=4.3.0",
"pymarkdownlnt>=0.9.32",
"pytest>=8.4.2",
"pytest>=9.0.3",
"pytest-asyncio>=1.1.0",
"pytest-cov>=6.2.1",
"pytest-xdist>=3.8.0",
Expand All @@ -389,5 +390,21 @@ dev = [
"types-tabulate>=0.9.0.20241207",
]

# Transient dependency pins — these are indirect dependencies that need security floors
# without polluting the public dependency list or downstream install footprints.
[tool.uv]
constraint-dependencies = [
"urllib3>=2.6.3",
"cryptography>=46.0.7",
"python-multipart>=0.0.26",
"authlib>=1.6.11",
"starlette>=0.49.1",
"python-dotenv>=1.2.2",
"requests>=2.33.0",
"Pygments>=2.20.0",
"filelock>=3.20.3",
"virtualenv>=20.36.1",
]

# Pre-commit hooks configuration (for reference)
# Create .pre-commit-config.yaml separately
2 changes: 1 addition & 1 deletion src/databeak/servers/discovery_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ async def inspect_data_around(
# Handle different index types from iterrows safely
row_index_val = int(orig_idx) if isinstance(orig_idx, int) else 0
record: dict[str, CsvCellValue] = {"__row_index__": row_index_val}
record.update(row_data.to_dict())
record.update({str(k): v for k, v in row_data.to_dict().items()})

# Handle pandas/numpy types
for key, value in record.items():
Expand Down
5 changes: 3 additions & 2 deletions src/databeak/utils/secure_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import operator
import re
import threading
from typing import Any, ClassVar
from typing import Any, ClassVar, cast

import numpy as np
import pandas as pd
Expand Down Expand Up @@ -659,6 +659,7 @@ def _evaluate_with_context(
# Use simpleeval for safe execution
self._evaluator.names.update(context)
result = self._evaluator.eval(expression)
result = cast(pd.Series, result)

# Ensure result is a pandas Series
if not isinstance(result, pd.Series):
Expand All @@ -685,7 +686,7 @@ def _evaluate_with_context(
f"Expression evaluation failed: {e}",
) from e

return result # type: ignore[no-any-return]
return result

def _evaluate_string_method(
self, expression: str, series: pd.Series, var_name: str
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/test_relaxed_integer_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ async def test_invalid_string_integer_rejected(databeak_client: Client[FastMCPTr
assert load_result.is_error is False

# Invalid string should be rejected (FastMCP wraps ValidationError in ToolError)
with pytest.raises(ToolError, match="Input validation error"):
with pytest.raises(ToolError, match="validation error"):
await databeak_client.call_tool(
"get_cell_value",
{"row_index": "abc", "column": "name"},
Expand All @@ -144,7 +144,7 @@ async def test_fractional_float_rejected(databeak_client: Client[FastMCPTranspor
assert load_result.is_error is False

# Non-integer float should be rejected (FastMCP wraps ValidationError in ToolError)
with pytest.raises(ToolError, match="Input validation error"):
with pytest.raises(ToolError, match="validation error"):
await databeak_client.call_tool(
"get_cell_value",
{"row_index": 1.5, "column": "name"},
Expand All @@ -160,7 +160,7 @@ async def test_empty_string_rejected(databeak_client: Client[FastMCPTransport])
assert load_result.is_error is False

# Empty string should be rejected (FastMCP wraps ValidationError in ToolError)
with pytest.raises(ToolError, match="Input validation error"):
with pytest.raises(ToolError, match="validation error"):
await databeak_client.call_tool(
"get_cell_value",
{"row_index": "", "column": "name"},
Expand Down
Loading
Loading