Repository navigation
fix: enhance folder permission checks by incorporating user group permissions #7884
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| """Folder tree honors permissions granted through user groups.""" | ||
|
|
||
| from types import SimpleNamespace | ||
| from unittest.mock import patch | ||
|
|
||
| from application.models import ApplicationFolder | ||
| from django.test import TestCase | ||
| from knowledge.models import KnowledgeFolder | ||
| from system_manage.models import WorkspaceUserGroupResourcePermission | ||
| from tools.models import ToolFolder | ||
| from users.models import User | ||
| from users.models.user_group import SystemUserGroup, SystemUserGroupRelation | ||
|
|
||
| from folders.serializers.folder import FolderTreeSerializer | ||
|
|
||
|
|
||
| class FolderTreeUserGroupPermissionTests(TestCase): | ||
| workspace_id = "00000000-0000-0000-0000-000000000010" | ||
| user_id = "00000000-0000-0000-0000-000000000011" | ||
| group_id = "00000000-0000-0000-0000-000000000012" | ||
| allowed_folder_id = "00000000-0000-0000-0000-000000000013" | ||
| other_folder_id = "00000000-0000-0000-0000-000000000014" | ||
| folder_types = ( | ||
| ("KNOWLEDGE", KnowledgeFolder), | ||
| ("APPLICATION", ApplicationFolder), | ||
| ("TOOL", ToolFolder), | ||
| ) | ||
|
|
||
| def setUp(self): | ||
| self.user = User.objects.create( | ||
| id=self.user_id, | ||
| username="folder-tree-user", | ||
| nick_name="folder tree user", | ||
| password="x", | ||
| role="USER", | ||
| ) | ||
| group = SystemUserGroup.objects.create(id=self.group_id, name="group B", workspace_id=self.workspace_id) | ||
| SystemUserGroupRelation.objects.create(user=self.user, group=group) | ||
|
|
||
| for source, folder_model in self.folder_types: | ||
| root = folder_model.objects.create(id=self.workspace_id, name="root", workspace_id=self.workspace_id) | ||
| folder_model.objects.create( | ||
| id=self.allowed_folder_id, name="111", workspace_id=self.workspace_id, parent=root | ||
| ) | ||
| folder_model.objects.create( | ||
| id=self.other_folder_id, name="other", workspace_id=self.workspace_id, parent=root | ||
| ) | ||
| WorkspaceUserGroupResourcePermission.objects.create( | ||
| workspace_id=self.workspace_id, | ||
| user_group=group, | ||
| auth_target_type=source, | ||
| target=self.allowed_folder_id, | ||
| permission_list=["VIEW"], | ||
| ) | ||
|
|
||
| @patch("folders.serializers.folder.is_workspace_manage", return_value=False) | ||
| def test_group_granted_folder_appears_in_each_resource_tree(self, _is_workspace_manage): | ||
| for source, _folder_model in self.folder_types: | ||
| with self.subTest(source=source): | ||
| result = FolderTreeSerializer( | ||
| data={"workspace_id": self.workspace_id, "source": source} | ||
| ).get_folder_tree(SimpleNamespace(id=self.user_id), name=None) | ||
|
|
||
| root = next(node for node in result if node["id"] == self.workspace_id) | ||
| child_ids = [child["id"] for child in root["children"]] | ||
| self.assertIn(self.allowed_folder_id, child_ids) | ||
| self.assertNotIn(self.other_folder_id, child_ids) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test is focused and readable, but there are several robustness issues and optimization opportunities. Key concerns
Optimization suggestions
Example improvement sketch@classmethod
def setUpTestData(cls):
cls.user = User.objects.create_user(
id=cls.user_id,
username="folder-tree-user",
nick_name="folder tree user",
password="x",
role="USER",
)
cls.group = SystemUserGroup.objects.create(
id=cls.group_id, name="group B", workspace_id=cls.workspace_id
)
SystemUserGroupRelation.objects.create(user=cls.user, group=cls.group)
cls.folder_ids = {}
for source, folder_model in cls.folder_types:
root_id = uuid.uuid4()
allowed_id = uuid.uuid4()
other_id = uuid.uuid4()
root = folder_model.objects.create(
id=root_id, name="root", workspace_id=cls.workspace_id
)
folder_model.objects.create(
id=allowed_id, name="111", workspace_id=cls.workspace_id, parent=root
)
folder_model.objects.create(
id=other_id, name="other", workspace_id=cls.workspace_id, parent=root
)
WorkspaceUserGroupResourcePermission.objects.create(
workspace_id=cls.workspace_id,
user_group=cls.group,
auth_target_type=source,
target=allowed_id,
permission_list=["VIEW"],
)
cls.folder_ids[source] = {
"root_id": root_id,
"allowed_id": allowed_id,
"other_id": other_id,
}And in the test, use Overall: the test covers the happy path, but it could be made more reliable by avoiding shared IDs across folder types, using the real user object, validating the serializer if appropriate, and strengthening the assertions. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an analysis of the code changes, highlighting potential issues, logic checks, and optimization suggestions.
1. Logic & Correctness
WorkspaceUserResourcePermissionOR viaGroupMembership(user_group__user_relations). This is standard RBAC (Role-Based Access Control) logic.permission_conditionScope: Ensure that the variablepermission_condition(a list like["VIEW", "ROLE"]) is correctly defined inside thehaving_read_permission_by_roleblock and accessible when building the queries for both users and groups. If it's defined conditionally, ensure the subsequent lines are only executed when appropriate.values_listEfficiency: Using.values_list("target", flat=True)is efficient because it avoids instantiating model objects.2. Potential Issues
ORconditions and subqueries, which is acceptable.WorkspaceUserResourcePermission(user_id, auth_target_type, workspace_id)WorkspaceUserGroupResourcePermission(user_group, auth_target_type, workspace_id)user_group__user_relations.current_userhas no direct or group permissions, theQ(id__in=...)clauses will filter nothing, but the| Q(id=self.data.get("workspace_id"))ensures at least the workspace root is included (assuming that’s intended behavior). Verify if users with no explicit permissions should indeed see the workspace root or not. Often, workspace visibility is controlled separately.3. Optimization & Code Quality Suggestions
auth_target_typeandworkspace_id. You could refactor slightly for readability, though the current version is clear enough.values_listcalls followed by combining Q objects, you could potentially combine the queries before evaluating. However, the current approach is fine. Here is a slightly more optimized pattern using a single combined query if the models support it directly, but since they are different models, separate queries are necessary.Suggested Refactor (Minor Readability Improvement)
Current code is fine, but wrapping the permission filters into helper methods or variables if used elsewhere would be better. For this snippet, it's okay as-is.
4. Final Verdict
✅ No critical bugs detected.
⚠️ Check Indexes: Ensure DB indexes to support the new
WorkspaceUserGroupResourcePermissionlookups, especially traversing relationships (user_group__user_relations__user_id).💡 Logic Check: Confirm business logic allows default visibility to
workspace_ideven without explicit folder permissions.Optimized Version (Optional)
If you want to slightly tighten the syntax:
This matches your current logic exactly. No functional change needed unless indexing is missing.