From 938098948f9a21eb72be2feb735951b83bb72942 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 22:58:18 +0000 Subject: [PATCH 01/11] chore(deps): bump pypdf in the pip group across 1 directory Bumps the pip group with 1 update in the / directory: [pypdf](https://github.com/py-pdf/pypdf). Updates `pypdf` from 6.1.3 to 6.4.0 - [Release notes](https://github.com/py-pdf/pypdf/releases) - [Changelog](https://github.com/py-pdf/pypdf/blob/main/CHANGELOG.md) - [Commits](https://github.com/py-pdf/pypdf/compare/6.1.3...6.4.0) --- updated-dependencies: - dependency-name: pypdf dependency-version: 6.4.0 dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6b31cc8db..bd5a75fbe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ dependencies = [ "xlrd==2.0.2", "xlwt==1.3.0", "pymupdf==1.26.3", - "pypdf==6.1.3", + "pypdf==6.4.0", "pydub==0.25.1", "pysilk==0.0.1", "gunicorn==23.0.0", From 75da3bd82ddc10c52bc8091884c6fbe14783fe27 Mon Sep 17 00:00:00 2001 From: liqiang-fit2cloud Date: Tue, 25 Nov 2025 10:58:17 +0800 Subject: [PATCH 02/11] refactor: format code. --- installer/sandbox.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/installer/sandbox.c b/installer/sandbox.c index fecdb27cf..55c794439 100644 --- a/installer/sandbox.c +++ b/installer/sandbox.c @@ -21,6 +21,8 @@ #include #define CONFIG_FILE ".sandbox.conf" +#define KEY_BANNED_HOSTS "SANDBOX_PYTHON_BANNED_HOSTS" +#define KEY_ALLOW_SUBPROCESS "SANDBOX_PYTHON_ALLOW_SUBPROCESS" static char *banned_hosts = NULL; static int allow_subprocess = 0; // 默认禁止 @@ -57,10 +59,10 @@ static void load_sandbox_config() { while (*value == ' ' || *value == '\t') value++; char *vend = value + strlen(value) - 1; while (vend > value && (*vend == ' ' || *vend == '\t')) *vend-- = '\0'; - if (strcmp(key, "SANDBOX_PYTHON_BANNED_HOSTS") == 0) { + if (strcmp(key, KEY_BANNED_HOSTS) == 0) { free(banned_hosts); banned_hosts = strdup(value); - } else if (strcmp(key, "SANDBOX_PYTHON_ALLOW_SUBPROCESS") == 0) { + } else if (strcmp(key, KEY_ALLOW_SUBPROCESS) == 0) { allow_subprocess = atoi(value); } } From 197d514cb44ace5e1a849f07f6ed7f6378478e45 Mon Sep 17 00:00:00 2001 From: liqiang-fit2cloud Date: Tue, 25 Nov 2025 14:33:13 +0800 Subject: [PATCH 03/11] refactor: clear all env from sandbox. --- apps/common/utils/tool_code.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/common/utils/tool_code.py b/apps/common/utils/tool_code.py index 45e532cc0..cc2571236 100644 --- a/apps/common/utils/tool_code.py +++ b/apps/common/utils/tool_code.py @@ -82,13 +82,14 @@ class ToolExecutor: python_paths = CONFIG.get_sandbox_python_package_paths().split(',') _exec_code = f""" try: - import sys, json, base64, builtins + import os, sys, json, base64, builtins path_to_exclude = ['/opt/py3/lib/python3.11/site-packages', '/opt/maxkb-app/apps'] sys.path = [p for p in sys.path if p not in path_to_exclude] sys.path += {python_paths} locals_v={'{}'} keywords={keywords} globals_v={'{}'} + os.environ.clear() exec({dedent(code_str)!a}, globals_v, locals_v) f_name, f = locals_v.popitem() for local in locals_v: @@ -180,16 +181,14 @@ except Exception as e: python_paths = CONFIG.get_sandbox_python_package_paths().split(',') code = self._generate_mcp_server_code(code_str, params) return f""" -import os -import sys -import logging +import os, sys, logging logging.basicConfig(level=logging.WARNING) logging.getLogger("mcp").setLevel(logging.ERROR) logging.getLogger("mcp.server").setLevel(logging.ERROR) - path_to_exclude = ['/opt/py3/lib/python3.11/site-packages', '/opt/maxkb-app/apps'] sys.path = [p for p in sys.path if p not in path_to_exclude] sys.path += {python_paths} +os.environ.clear() exec({dedent(code)!a}) """ From 7da64a2268b275df9057b6aadadef37a744f173e Mon Sep 17 00:00:00 2001 From: zhangzhanwei Date: Tue, 25 Nov 2025 15:19:49 +0800 Subject: [PATCH 04/11] feat: Filter user by role --- .../serializers/user_resource_permission.py | 32 +++++++++-- ...get_resource_user_permission_detail_ee.sql | 55 +++++++++++-------- .../views/user_resource_permission.py | 1 + .../resource-authorization-drawer/index.vue | 32 +++++------ 4 files changed, 72 insertions(+), 48 deletions(-) diff --git a/apps/system_manage/serializers/user_resource_permission.py b/apps/system_manage/serializers/user_resource_permission.py index b34b8544e..2efaa5a62 100644 --- a/apps/system_manage/serializers/user_resource_permission.py +++ b/apps/system_manage/serializers/user_resource_permission.py @@ -9,6 +9,7 @@ import json import os +from django.contrib.postgres.fields import ArrayField from django.core.cache import cache from django.db import models from django.db.models import QuerySet, Q, TextField @@ -343,10 +344,13 @@ class ResourceUserPermissionSerializer(serializers.Serializer): "role": models.CharField(), "role_setting.type": models.CharField(), "user_role_relation.workspace_id": models.CharField(), + 'tmp.type_list': ArrayField(models.CharField()), + 'tmp.role_name_list_str': models.CharField() })) nick_name = instance.get('nick_name') username = instance.get('username') + role_name = instance.get('role') permission = instance.get('permission') query_p_list = [None if p == "NOT_AUTH" else p for p in permission] @@ -375,15 +379,31 @@ class ResourceUserPermissionSerializer(serializers.Serializer): **{"u.id__in": QuerySet(workspace_user_role_mapping_model).filter( workspace_id=self.data.get('workspace_id')).values("user_id")}) if is_x_pack_ee: - user_query_set = user_query_set.filter( - **{'role_setting.type': "USER", 'user_role_relation.workspace_id': self.data.get('workspace_id')}) + user_query_set = user_query_set.filter(**{ + "tmp.type_list__contains": ["USER"] + }) + role_name_and_type_query_set = QuerySet(model=get_dynamics_model({ + 'user_role_relation.workspace_id': models.CharField(), + })).filter(**{ + "user_role_relation.workspace_id": self.data.get('workspace_id'), + }) + if role_name: + user_query_set = user_query_set.filter( + **{'tmp.role_name_list_str__icontains': str(role_name)} + ) + + return { + 'workspace_user_resource_permission_query_set': workspace_user_resource_permission_query_set, + 'user_query_set': user_query_set, + 'role_name_and_type_query_set': role_name_and_type_query_set + } else: user_query_set = user_query_set.filter( **{'role': "USER"}) - return { - 'workspace_user_resource_permission_query_set': workspace_user_resource_permission_query_set, - 'user_query_set': user_query_set - } + return { + 'workspace_user_resource_permission_query_set': workspace_user_resource_permission_query_set, + 'user_query_set': user_query_set + } def list(self, instance, with_valid=True): if with_valid: diff --git a/apps/system_manage/sql/get_resource_user_permission_detail_ee.sql b/apps/system_manage/sql/get_resource_user_permission_detail_ee.sql index a90050016..f910e9479 100644 --- a/apps/system_manage/sql/get_resource_user_permission_detail_ee.sql +++ b/apps/system_manage/sql/get_resource_user_permission_detail_ee.sql @@ -1,34 +1,41 @@ SELECT - distinct(u.id), + DISTINCT u.id, u.nick_name, u.username, - case - when - wurp."permission" is null then 'NOT_AUTH' - else wurp."permission" - end + tmp.role_name_list AS role_name, + CASE + WHEN wurp."permission" IS NULL THEN 'NOT_AUTH' + ELSE wurp."permission" + END AS permission FROM public."user" u LEFT JOIN ( SELECT - user_id , - (case - when auth_type = 'ROLE' - and 'ROLE' = any( permission_list) then 'ROLE' - when auth_type = 'RESOURCE_PERMISSION_GROUP' - and 'MANAGE'= any(permission_list) then 'MANAGE' - when auth_type = 'RESOURCE_PERMISSION_GROUP' - and 'VIEW' = any( permission_list) then 'VIEW' - else null - end) as "permission" + user_id, + CASE + WHEN auth_type = 'ROLE' + AND 'ROLE' = ANY(permission_list) THEN 'ROLE' + WHEN auth_type = 'RESOURCE_PERMISSION_GROUP' + AND 'MANAGE' = ANY(permission_list) THEN 'MANAGE' + WHEN auth_type = 'RESOURCE_PERMISSION_GROUP' + AND 'VIEW' = ANY(permission_list) THEN 'VIEW' + ELSE NULL + END AS "permission" FROM workspace_user_resource_permission - ${workspace_user_resource_permission_query_set} - ) wurp -ON - u.id = wurp.user_id -left join user_role_relation user_role_relation -on user_role_relation.user_id = u.id -left join role_setting role_setting -on role_setting.id = user_role_relation.role_id + ${workspace_user_resource_permission_query_set} +) wurp ON u.id = wurp.user_id +LEFT JOIN ( + SELECT + ARRAY_AGG(role_setting.role_name) AS role_name_list, + ARRAY_AGG(role_setting.role_name)::text AS role_name_list_str, + ARRAY_AGG(role_setting.type) AS type_list, + user_role_relation.user_id + FROM user_role_relation user_role_relation + LEFT JOIN role_setting role_setting + ON role_setting.id = user_role_relation.role_id + ${role_name_and_type_query_set} + GROUP BY + user_role_relation.user_id) tmp +ON u.id = tmp.user_id ${user_query_set} \ No newline at end of file diff --git a/apps/system_manage/views/user_resource_permission.py b/apps/system_manage/views/user_resource_permission.py index ba2c56252..68cd61459 100644 --- a/apps/system_manage/views/user_resource_permission.py +++ b/apps/system_manage/views/user_resource_permission.py @@ -196,6 +196,7 @@ class WorkspaceResourceUserPermissionView(APIView): return result.success(ResourceUserPermissionSerializer( data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, } ).page({'username': request.query_params.get("username"), + 'role': request.query_params.get("role"), 'nick_name': request.query_params.get("nick_name"), 'permission': request.query_params.getlist("permission[]")}, current_page, page_size, )) diff --git a/ui/src/components/resource-authorization-drawer/index.vue b/ui/src/components/resource-authorization-drawer/index.vue index 0eb8e76e1..9ae6af2c0 100644 --- a/ui/src/components/resource-authorization-drawer/index.vue +++ b/ui/src/components/resource-authorization-drawer/index.vue @@ -23,6 +23,7 @@ + - + - +