# #region Test.Agent.Feature035 [C:3] [TYPE Module] [SEMANTICS test,agent-chat,context,tools,rbac] # @BRIEF Contract tests for feature 035 context filtering, invocation RBAC, and tool response summarisation. # @RELATION BINDS_TO -> [AgentChat.ToolFilter] # @RELATION BINDS_TO -> [AgentChat.Tools] # @TEST_EDGE: dashboard_context_admin -> Dashboard affinity keeps dashboard tools plus mandatory capabilities. # @TEST_EDGE: dashboard_context_viewer -> RBAC removes admin-only dashboard tools. # @TEST_EDGE: invocation_guard_denied -> Mutating tool rejects before HTTP side effect. import pytest from types import SimpleNamespace from ss_tools.agent._tool_filter import build_tool_pipeline from ss_tools.agent.context import set_user_role from ss_tools.agent.tools import _guard_tool_permission, _summarise_response def _tools(names: list[str]) -> list[SimpleNamespace]: return [SimpleNamespace(name=name) for name in names] # #region test_dashboard_context_filters_tools [C:2] [TYPE Function] # @BRIEF Dashboard context keeps only dashboard-affinity tools and mandatory capabilities. def test_dashboard_context_filters_tools(): tools = _tools([ "search_dashboards", "get_health_summary", "deploy_dashboard", "superset_execute_sql", "run_backup", "show_capabilities", ]) result = [tool.name for tool in build_tool_pipeline(tools, "admin", "dashboard")] assert result == [ "search_dashboards", "get_health_summary", "deploy_dashboard", "show_capabilities", ] # #endregion test_dashboard_context_filters_tools # #region test_dashboard_context_viewer_removes_admin_tools [C:2] [TYPE Function] # @BRIEF Viewer role removes admin-only tools even when they are dashboard-affinity tools. def test_dashboard_context_viewer_removes_admin_tools(): tools = _tools([ "search_dashboards", "deploy_dashboard", "execute_migration", "show_capabilities", ]) result = [tool.name for tool in build_tool_pipeline(tools, "viewer", "dashboard")] assert result == ["search_dashboards", "show_capabilities"] # #endregion test_dashboard_context_viewer_removes_admin_tools # #region test_invocation_guard_blocks_mutating_tool [C:2] [TYPE Function] # @BRIEF Invocation guard rejects admin-only tools for non-admin role before side effects. def test_invocation_guard_blocks_mutating_tool(): set_user_role("viewer") with pytest.raises(PermissionError, match="PERMISSION_DENIED:deploy_dashboard:admin:viewer"): _guard_tool_permission("deploy_dashboard") # #endregion test_invocation_guard_blocks_mutating_tool # #region test_summarise_response_preserves_json_array_shape [C:2] [TYPE Function] # @BRIEF Large JSON arrays are summarised as top-N plus total count, not cut mid-structure. def test_summarise_response_preserves_json_array_shape(): text = "[" + ",".join(f'{{"id":{idx},"name":"dashboard-{idx}"}}' for idx in range(20)) + "]" summary = _summarise_response(text, limit=100) assert summary.startswith("Found 20 items:") assert "dashboard-0" in summary assert "15 more items" in summary # #endregion test_summarise_response_preserves_json_array_shape # #endregion Test.Agent.Feature035