RBAC Initialization#
Overview#
Dify's enterprise RBAC system must be explicitly initialized for every App, Dataset, and Agent at the moment of creation. If initialization is skipped, the resource has no access record β non-creator team members hit a 403 when opening it. (The creator is short-circuited by maintainer/owner checks and never sees the error.) The primary tracking issue is #39379 .
The initialization sequence has three steps :
replace_whitelist(AppAccess/DatasetAccess/AgentAccess) β seeds the whitelist.automatic_include_workspace_membersisTruefor apps and agents,Falsefor datasets.try_sync_creator_access_policy_member_bindingsβ wires the creator into any applicable access-policy group .initialize_created_app_rbac_access_task(async Celery) β backfills current workspace members into the whitelist. Apps and agents run this task; datasets do not .
This sequence is fully wired only into the primary console create controllers. Every other entry point constructs the resource directly and silently omits it .
App Creation Coverage#
| Entry point | RBAC initialized? | Code location |
|---|---|---|
Console POST /apps | β Yes | app.py:724β733 |
Agent App create (POST /agent) | β Yes | roster_service.py:314β322 |
| DSL import (YAML) | β Yes (agents only) | app_dsl_service.py:460β479 |
| App package import (file) | β Yes (agents only) | app_import.py, app_dsl_service.py |
| App package import (URL) | β Yes (agents only) | app_import.py, app_dsl_service.py |
Agent package import (.ifpkg) | β Yes | roster_package_importer.py:410 |
| Agent App duplication | β Yes | roster_service.py:947β977 |
| Workflow β Advanced Chat/Workflow conversion | β No | workflow_converter.py:93β119 |
Console create (AppService.create_app) runs all three initialization steps and dispatches initialize_created_app_rbac_access_task. For agent-mode apps it calls initialize_agent_rbac_access instead of the app-typed path .
Agent paths (create, duplicate, .ifpkg import, composer save-to-roster) now all call the shared initialize_agent_rbac_access helper . DSL import initializes RBAC for agent apps; non-agent DSL imports still skip it .
App package imports (ordinary .ifpkg files, both Workflow and Chatflow, from file upload or URL, including overwrite mode) are routed through AppPackageService.read_package, which validates the archive and extracts bundled inline Agent Skills and configuration files packaged with workflow/chatflow exports. The prepared package is passed to import_app for resource remapping and recreation of node-owned Agents, then delegates to the existing DSL import path. These imports follow the same RBAC initialization behavior as YAML DSL imports: agent packages initialize RBAC, non-agent packages skip it.
Workflow conversion (WorkflowConverter.convert_to_workflow) creates a bare App, commits, fires app_was_created, and returns β no RBAC calls are made . This is the remaining gap for app creation.
Dataset Creation Coverage#
| Entry point | RBAC initialized? | Notes |
|---|---|---|
| Console empty dataset | β Partial | DatasetAccess.replace_whitelist with automatic_include_workspace_members=False; no async task |
Public API (service_api) create | β Partial | Same as above |
File upload (save_document_without_dataset_id) | β Partial | Fixed in PR #40599 |
| RAG pipeline dataset import | β Partial | Same partial init |
| External knowledge base | β Yes | Fixed in PR #39930 |
| RAG pipeline DSL import | β Yes | Fixed in PR #42430 |
| RAG pipeline empty dataset | β No | dataset_service.py:532 |
As of PR #42430, all dataset creation paths use automatic_include_workspace_members=False. Workspace members must be explicitly granted dataset access; they are no longer automatically included at creation time .
Two-Layer Permission Problem#
Datasets have two independent access layers that must stay in sync :
- Legacy enum β
Dataset.permission(only_me/all_team_members/partial_members), enforced bycheck_dataset_permission()on every request. - RBAC whitelist β
DatasetAccessconfig in the enterprise RBAC service, gated byRBAC_ENABLED.
When RBAC is enabled, both layers run independently. Mismatches cause 403 errors for correctly-permissioned users. The specific failure mode: a dataset created via file upload defaults to permission=only_me and has no RBAC whitelist β even after assigning "Partial team members" in the RBAC UI, the legacy gate rejects first .
check_dataset_permission() has no RBAC_ENABLED branch. PR #41022 added an if not dify_config.RBAC_ENABLED guard to the dataset GET endpoint in datasets.py, but 8 call sites in datasets_document.py remain unguarded .
The console empty-dataset create path forces permission=ALL_TEAM to make the legacy gate a pass-through; other create paths do not .
Workspace Member Join Path#
When a new member joins a workspace, TenantService.create_tenant_member dispatches sync_joined_workspace_member_rbac_access_task under these conditions :
membership_created=True(not a role update)RBAC_ENABLEDis true- Role is not OWNER
- Account is not PENDING
The task iterates all apps, datasets, and agents in the workspace in batches of 500, fetches whitelist configs via ResourceWhitelistConfigs.batch_get, and appends the new member only to resources with automatic_include_workspace_members=True .
Impact of the False default for datasets: Since all dataset creation paths now set automatic_include_workspace_members=False, members who join a workspace after dataset creation gain no automatic access to existing datasets .
Root Cause, Open Gaps, and Key Files#
Root cause: RBAC-on-create logic is duplicated inline in individual controllers rather than extracted into a shared helper. Any new creation entry point that doesn't copy the boilerplate silently ships with no access records .
Agent creation is now partially consolidated under initialize_agent_rbac_access (in api/services/rbac_agent_access_service.py). App and dataset creation paths still inline the logic.
Remaining Gaps#
| Gap | Location |
|---|---|
| Workflow β App conversion skips RBAC init | workflow_converter.py:93β119 |
| RAG pipeline empty dataset skips RBAC init | dataset_service.py:532 |
8 check_dataset_permission call sites lack RBAC_ENABLED guard | datasets_document.py |
Non-agent DSL imports (YAML and ordinary .ifpkg packages) skip RBAC init | app_dsl_service.py, app_import.py |
Key Files#
| File | Role |
|---|---|
api/controllers/console/app/app.py | Primary console app creation β reference implementation for full RBAC init |
api/controllers/console/app/app_import.py | App import entry point β routes .ifpkg packages through AppPackageService or RosterAgentPackageImporter |
api/services/app_service.py | AppService.create_app β branches between app and agent RBAC init |
api/services/app_dsl_service.py | DSL import β RBAC init for agent apps only |
api/services/app_package_service.py | Ordinary app package export/import β validates archives and prepares bundled Agent resources for delegation to import_app |
api/services/agent/roster_service.py | Agent create/duplicate β calls initialize_agent_rbac_access |
api/services/workflow/workflow_converter.py | Workflow conversion β missing RBAC init |
api/services/dataset_service.py | check_dataset_permission, dataset create helpers |
api/services/enterprise/rbac_service.py | try_sync_creator_access_policy_member_bindings, AppAccess/DatasetAccess/AgentAccess whitelist APIs |
api/tasks/initialize_created_app_rbac_access_task.py | Celery tasks: initialize_created_app_rbac_access_task, sync_joined_workspace_member_rbac_access_task |
api/services/account_service.py | TenantService.create_tenant_member β member-join RBAC dispatch |
api/controllers/console/datasets/datasets.py | Dataset GET with RBAC_ENABLED guard (PR #41022) |
api/controllers/console/datasets/datasets_document.py | 8 unguarded check_dataset_permission call sites |
api/services/rag_pipeline/rag_pipeline_dsl_service.py | RAG pipeline DSL import β RBAC init fixed in PR #42430 |
Related Issues#
- #39379 β Primary tracking issue (partially open)
- #42429 β
automatic_include_workspace_membersshould beFalsefor datasets - #38910 β
all_team_membersβ workspace member sync ; fixed in PR #39735 - PR #42430 β datasets: set
automatic_include_workspace_members=False, fix RAG pipeline DSL import - PR #39227 β dataset permission β all team β update RBAC config