Dataset Access Control#
RAGFlow controls dataset (knowledgebase) visibility at two levels: ownership and team sharing. Every dataset carries a permission field on the Knowledgebase model that takes one of two values defined by the TenantPermission enum:
| Value | Meaning |
|---|---|
"me" (default) | Visible only to the owning tenant |
"team" | Visible to all users who have joined the owning tenant |
The permission field defaults to "me" . It can be set at creation time or updated via PUT /datasets/<dataset_id> . The SDK exposes it as a top-level field on the DataSet object .
UserTenant and Team Membership#
Cross-tenant sharing relies on the UserTenant junction table, which records each user's membership in tenants they did not create:
user_id— the accessing usertenant_id— the tenant being joinedrole— one ofowner,admin,normal,invite(defined inUserTenantRole)status—"1"(valid) or"0"(wasted)
TenantService.get_joined_tenants_by_user_id(user_id) returns all tenants where the user holds a NORMAL role and status = "1". This is the key query behind every team-permission check.
Permission Enforcement#
Core access check: KnowledgebaseService.accessible()#
All read operations and most write operations go through KnowledgebaseService.accessible(kb_id, user_id), which implements this logic:
- Fetch the knowledgebase record; return
Falseif not found orstatus != VALID. - If
kb.tenant_id == user_id→ owner access, returnTrue. - If
kb.permission != "team"→ returnFalse. - Otherwise, call
TenantService.get_joined_tenants_by_user_id(user_id)and returnTrueonly if the KB'stenant_idappears in the result.
This same logic is also encapsulated in the standalone helper check_kb_team_permission(kb, other) used by the file-permission layer.
Listing datasets: _visibility_and_status_filter()#
When listing datasets, KnowledgebaseService._visibility_and_status_filter(joined_tenant_ids, user_id) produces a single Peewee WHERE clause:
(tenant_id IN joined_tenant_ids AND permission = 'team')
OR tenant_id = user_id
AND status = VALID
This is applied by get_list(), get_by_tenant_ids(), get_accessible_ids(), and get_owner_filter().
In the service layer, list_datasets() pre-computes joined_tenant_ids via TenantService.get_joined_tenants_by_user_id() before calling KnowledgebaseService.get_list().
Delete: owner-only#
Delete is stricter than read. _delete_datasets_sync() uses KnowledgebaseService.get_or_none(id=kb_id, tenant_id=tenant_id) — a direct equality check against tenant_id, not the broader accessible() check. Team members can read a shared dataset but cannot delete it .
Update: accessible check#
update_dataset() calls KnowledgebaseService.get_kb_by_id(dataset_id, tenant_id), which internally calls accessible(). Team members with permission = "team" can update a dataset they can see .
Metadata configuration: owner-only#
get_auto_metadata() and update_auto_metadata() use KnowledgebaseService.get_or_none(id=dataset_id, tenant_id=tenant_id) — a strict owner check, not the team-accessible path .
Access Control by Operation#
| Operation | Check Used | Team Members Allowed? |
|---|---|---|
| List / GET dataset | accessible() (via get_kb_by_id) | ✅ if permission = "team" |
Update dataset (PUT) | accessible() (via get_kb_by_id) | ✅ if permission = "team" |
Delete dataset (DELETE) | get_or_none(tenant_id=...) (owner only) | ❌ |
| Get/update auto-metadata config | get_or_none(tenant_id=...) (owner only) | ❌ |
| Search / retrieval | accessible() | ✅ if permission = "team" |
| Tags, graphs, artifacts | accessible() | ✅ if permission = "team" |
For bulk list filtering, KnowledgebaseService.get_accessible_ids() is used to silently drop denied IDs rather than returning an error .
Key Files and Entry Points#
| File | Purpose |
|---|---|
api/db/db_models.py | Knowledgebase model — permission, tenant_id, created_by fields |
api/db/__init__.py | TenantPermission (me/team) and UserTenantRole enums |
api/db/db_models.py | UserTenant junction table |
api/db/services/knowledgebase_service.py | accessible(), _visibility_and_status_filter(), get_kb_by_id() |
api/db/services/user_service.py | TenantService.get_joined_tenants_by_user_id() |
api/common/check_team_permission.py | check_kb_team_permission() helper for file-layer checks |
api/apps/services/dataset_api_service.py | Service functions enforcing access per operation |
api/apps/restful_apis/dataset_api.py | REST endpoint definitions (POST, DELETE, PUT, GET) |