Files
ss-tools/agent/tests/test_agent/test_feature_035_contracts.py
root 632b730fff chore: migrate GRACE-Poly anchors to hierarchical dotted naming
Systematic rename of all semantic anchors (#region, [DEF], @RELATION)
across 1400+ files — backend Python, frontend Svelte/TS, specs, docs:
- Flat anchors become Namespace.Module.Entity
- @RELATION references updated to match new anchor paths
- Zero business logic changes
2026-07-22 11:48:15 +03:00

83 lines
3.2 KiB
Python

# #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.Agent.TestDashboardContextFiltersTools [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.Agent.TestDashboardContextFiltersTools
# #region Test.Agent.TestDashboardContextViewerRemovesAdminTools [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.Agent.TestDashboardContextViewerRemovesAdminTools
# #region Test.Agent.TestInvocationGuardBlocksMutatingTool [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.Agent.TestInvocationGuardBlocksMutatingTool
# #region Test.Agent.TestSummariseResponsePreservesJsonArrayShape [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.Agent.TestSummariseResponsePreservesJsonArrayShape
# #endregion Test.Agent.Feature035