feat(assistant): align tool visibility with route audiences
This commit is contained in:
@@ -375,6 +375,68 @@ describe("assistant router tool gating", () => {
|
|||||||
expect(userNames).not.toContain("get_project_computation_graph");
|
expect(userNames).not.toContain("get_project_computation_graph");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps planning read tools behind the explicit planning permission", () => {
|
||||||
|
const userWithoutPlanning = getToolNames([], SystemRole.USER);
|
||||||
|
const userWithPlanning = getToolNames([PermissionKey.VIEW_PLANNING], SystemRole.USER);
|
||||||
|
|
||||||
|
expect(userWithoutPlanning).not.toContain("list_allocations");
|
||||||
|
expect(userWithoutPlanning).not.toContain("list_demands");
|
||||||
|
expect(userWithoutPlanning).not.toContain("check_resource_availability");
|
||||||
|
expect(userWithPlanning).toContain("list_allocations");
|
||||||
|
expect(userWithPlanning).toContain("list_demands");
|
||||||
|
expect(userWithPlanning).toContain("check_resource_availability");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps controller-only project and dashboard reads hidden from plain users", () => {
|
||||||
|
const controllerNames = getToolNames([
|
||||||
|
PermissionKey.VIEW_COSTS,
|
||||||
|
PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
|
||||||
|
], SystemRole.CONTROLLER);
|
||||||
|
const userNames = getToolNames([
|
||||||
|
PermissionKey.VIEW_COSTS,
|
||||||
|
PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
|
||||||
|
PermissionKey.VIEW_PLANNING,
|
||||||
|
], SystemRole.USER);
|
||||||
|
|
||||||
|
expect(controllerNames).toContain("search_projects");
|
||||||
|
expect(controllerNames).toContain("get_project");
|
||||||
|
expect(controllerNames).toContain("get_statistics");
|
||||||
|
expect(controllerNames).toContain("get_dashboard_detail");
|
||||||
|
expect(controllerNames).toContain("get_skill_gaps");
|
||||||
|
expect(controllerNames).toContain("get_project_health");
|
||||||
|
expect(controllerNames).toContain("get_budget_forecast");
|
||||||
|
expect(userNames).not.toContain("search_projects");
|
||||||
|
expect(userNames).not.toContain("get_project");
|
||||||
|
expect(userNames).not.toContain("get_statistics");
|
||||||
|
expect(userNames).not.toContain("get_dashboard_detail");
|
||||||
|
expect(userNames).not.toContain("get_skill_gaps");
|
||||||
|
expect(userNames).not.toContain("get_project_health");
|
||||||
|
expect(userNames).not.toContain("get_budget_forecast");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requires both controller role and advanced assistant access for timeline detail tools", () => {
|
||||||
|
const controllerWithAdvanced = getToolNames([
|
||||||
|
PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
|
||||||
|
], SystemRole.CONTROLLER);
|
||||||
|
const controllerWithoutAdvanced = getToolNames([], SystemRole.CONTROLLER);
|
||||||
|
const userWithAdvanced = getToolNames([
|
||||||
|
PermissionKey.USE_ASSISTANT_ADVANCED_TOOLS,
|
||||||
|
], SystemRole.USER);
|
||||||
|
|
||||||
|
expect(controllerWithAdvanced).toContain("get_timeline_entries_view");
|
||||||
|
expect(controllerWithAdvanced).toContain("get_timeline_holiday_overlays");
|
||||||
|
expect(controllerWithAdvanced).toContain("get_project_timeline_context");
|
||||||
|
expect(controllerWithAdvanced).toContain("preview_project_shift");
|
||||||
|
expect(controllerWithoutAdvanced).not.toContain("get_timeline_entries_view");
|
||||||
|
expect(controllerWithoutAdvanced).not.toContain("get_timeline_holiday_overlays");
|
||||||
|
expect(controllerWithoutAdvanced).not.toContain("get_project_timeline_context");
|
||||||
|
expect(controllerWithoutAdvanced).not.toContain("preview_project_shift");
|
||||||
|
expect(userWithAdvanced).not.toContain("get_timeline_entries_view");
|
||||||
|
expect(userWithAdvanced).not.toContain("get_timeline_holiday_overlays");
|
||||||
|
expect(userWithAdvanced).not.toContain("get_project_timeline_context");
|
||||||
|
expect(userWithAdvanced).not.toContain("preview_project_shift");
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps timeline write parity tools behind manager/admin role, manageAllocations, and advanced assistant access", () => {
|
it("keeps timeline write parity tools behind manager/admin role, manageAllocations, and advanced assistant access", () => {
|
||||||
const managerNames = getToolNames([
|
const managerNames = getToolNames([
|
||||||
PermissionKey.MANAGE_ALLOCATIONS,
|
PermissionKey.MANAGE_ALLOCATIONS,
|
||||||
|
|||||||
@@ -224,8 +224,26 @@ const COST_TOOLS = new Set([
|
|||||||
"find_best_project_resource",
|
"find_best_project_resource",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/** Tools that follow planningReadProcedure access rules in the main API. */
|
||||||
|
const PLANNING_READ_TOOLS = new Set([
|
||||||
|
"list_allocations",
|
||||||
|
"list_demands",
|
||||||
|
"check_resource_availability",
|
||||||
|
]);
|
||||||
|
|
||||||
/** Tools that follow controllerProcedure access rules in the main API. */
|
/** Tools that follow controllerProcedure access rules in the main API. */
|
||||||
const CONTROLLER_ONLY_TOOLS = new Set([
|
const CONTROLLER_ONLY_TOOLS = new Set([
|
||||||
|
"search_projects",
|
||||||
|
"get_project",
|
||||||
|
"get_timeline_entries_view",
|
||||||
|
"get_timeline_holiday_overlays",
|
||||||
|
"get_project_timeline_context",
|
||||||
|
"preview_project_shift",
|
||||||
|
"get_statistics",
|
||||||
|
"get_dashboard_detail",
|
||||||
|
"get_skill_gaps",
|
||||||
|
"get_project_health",
|
||||||
|
"get_budget_forecast",
|
||||||
"query_change_history",
|
"query_change_history",
|
||||||
"get_entity_timeline",
|
"get_entity_timeline",
|
||||||
"export_resources_csv",
|
"export_resources_csv",
|
||||||
@@ -356,6 +374,9 @@ export function getAvailableAssistantTools(permissions: Set<PermissionKey>, user
|
|||||||
if (CONTROLLER_ONLY_TOOLS.has(toolName) && !hasControllerAccess) {
|
if (CONTROLLER_ONLY_TOOLS.has(toolName) && !hasControllerAccess) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (PLANNING_READ_TOOLS.has(toolName) && !permissions.has(PermissionKey.VIEW_PLANNING)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (COST_TOOLS.has(toolName) && !permissions.has(PermissionKey.VIEW_COSTS)) {
|
if (COST_TOOLS.has(toolName) && !permissions.has(PermissionKey.VIEW_COSTS)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user