From d87764b0f833082cb29630e6f8856305c50fc8dd Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Wed, 24 Jun 2026 17:56:28 +0800 Subject: [PATCH] feat: filter dataset operator and add miss permission key (#37867) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/controllers/console/workspace/rbac.py | 30 ++++++++++--------- api/services/enterprise/rbac_service.py | 7 +++++ .../console/workspace/test_rbac.py | 4 +-- .../services/enterprise/test_rbac_service.py | 11 +++++-- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/api/controllers/console/workspace/rbac.py b/api/controllers/console/workspace/rbac.py index f672833061a..c3a3420b908 100644 --- a/api/controllers/console/workspace/rbac.py +++ b/api/controllers/console/workspace/rbac.py @@ -201,21 +201,23 @@ def _legacy_workspace_roles( This keeps the new `/rbac/roles` endpoint compatible with the original Dify role model when enterprise RBAC is disabled. """ - - legacy_roles = [ - svc.RBACRole( - id=role_name, - tenant_id="", - type=svc.RBACRoleType.WORKSPACE.value, - category="global_system_default", - name=role_name, - description="", - is_builtin=True, - permission_keys=list(dict.fromkeys(_LEGACY_ROLE_PERMISSION_KEYS[role_name])), - role_tag="owner" if role_name == "owner" else "", + legacy_roles = [] + for role_name in ("owner", "admin", "editor", "normal", "dataset_operator"): + if not dify_config.DATASET_OPERATOR_ENABLED and role_name == "dataset_operator": + continue + legacy_roles.append( + svc.RBACRole( + id=role_name, + tenant_id="", + type=svc.RBACRoleType.WORKSPACE.value, + category="global_system_default", + name=role_name, + description="", + is_builtin=True, + permission_keys=list(dict.fromkeys(_LEGACY_ROLE_PERMISSION_KEYS[role_name])), + role_tag="owner" if role_name == "owner" else "", + ) ) - for role_name in ("owner", "admin", "editor", "normal", "dataset_operator") - ] if not include_owner: legacy_roles = [r for r in legacy_roles if r.name != "owner"] diff --git a/api/services/enterprise/rbac_service.py b/api/services/enterprise/rbac_service.py index b5585932b29..af6f79948d7 100644 --- a/api/services/enterprise/rbac_service.py +++ b/api/services/enterprise/rbac_service.py @@ -379,6 +379,9 @@ _LEGACY_WORKSPACE_EDITOR_KEYS: list[str] = [ "snippets.create_and_modify", "tool.manage", "snippets.create_and_modify", + "billing.view", + "billing.subscription.manage", + "billing.manage", ] _LEGACY_WORKSPACE_NORMAL_KEYS: list[str] = [ @@ -386,6 +389,9 @@ _LEGACY_WORKSPACE_NORMAL_KEYS: list[str] = [ "plugin.install", "credential.use", "app_library.access", + "billing.view", + "billing.subscription.manage", + "billing.manage", ] _LEGACY_WORKSPACE_DATASET_OPERATOR_KEYS: list[str] = [ @@ -834,6 +840,7 @@ class RBACService: options: ListOption | None = None, ) -> Paginated[RBACRole]: params = (options or ListOption()).to_params({"include_owner": include_owner}) + params["dataset_operator_enabled"] = dify_config.DATASET_OPERATOR_ENABLED data = _inner_call( "GET", f"{_INNER_PREFIX}/roles", diff --git a/api/tests/unit_tests/controllers/console/workspace/test_rbac.py b/api/tests/unit_tests/controllers/console/workspace/test_rbac.py index d78bc1fc6dd..2960bfef324 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_rbac.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_rbac.py @@ -201,10 +201,10 @@ class TestPaginationMapping: }, ] assert response["pagination"] == { - "total_count": 5, + "total_count": 4, "per_page": 2, "current_page": 1, - "total_pages": 3, + "total_pages": 2, } mock_list.assert_not_called() diff --git a/api/tests/unit_tests/services/enterprise/test_rbac_service.py b/api/tests/unit_tests/services/enterprise/test_rbac_service.py index 5dc68008840..ef786c944e1 100644 --- a/api/tests/unit_tests/services/enterprise/test_rbac_service.py +++ b/api/tests/unit_tests/services/enterprise/test_rbac_service.py @@ -86,21 +86,26 @@ class TestRoles: call = _call_args(mock_send) assert call.method == "GET" assert call.endpoint == "/rbac/roles" - assert call.params == {"page_number": 2, "results_per_page": 50, "reverse": "true"} + assert call.params == { + "dataset_operator_enabled": False, + "page_number": 2, + "results_per_page": 50, + "reverse": "true", + } assert out.pagination assert out.pagination.total_count == 1 def test_list_omits_params_when_default(self, mock_send: MagicMock): mock_send.return_value = {"data": [], "pagination": None} svc.RBACService.Roles.list("tenant-1") - assert _call_args(mock_send).params is None + assert _call_args(mock_send).params is not None def test_list_forwards_include_owner(self, mock_send: MagicMock): mock_send.return_value = {"data": [], "pagination": None} svc.RBACService.Roles.list("tenant-1", include_owner=1) - assert _call_args(mock_send).params == {"include_owner": 1} + assert _call_args(mock_send).params == {"dataset_operator_enabled": False, "include_owner": 1} def test_list_coerces_null_permission_keys(self, mock_send: MagicMock): mock_send.return_value = {