feat(rbac): agent RBAC/ACL scenes and resource-locator check bundles (#41768)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Xiyuan Chenandautofix-ci[bot] authored and GitHub committed 2026-09-07 04:39:43 +00:00
1 parent 60e983c493
commit 86134ea99e
152 files changed
+5360 -3405

No files matched your search

+11 -11
View File
@@ -15,11 +15,11 @@ from flask_restx import Resource
from pydantic import BaseModel, Field
from controllers.common.fields import SuccessResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.console import console_ns
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
is_admin_or_owner_required,
model_validate,
@@ -235,7 +235,7 @@ class EndpointCollectionApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -267,7 +267,7 @@ class DeprecatedEndpointCreateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -291,7 +291,7 @@ class EndpointListApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -321,7 +321,7 @@ class EndpointListForSinglePluginApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -355,7 +355,7 @@ class EndpointItemApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -377,7 +377,7 @@ class EndpointItemApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -410,7 +410,7 @@ class DeprecatedEndpointDeleteApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -443,7 +443,7 @@ class DeprecatedEndpointUpdateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -468,7 +468,7 @@ class EndpointEnableApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -493,7 +493,7 @@ class EndpointDisableApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user_id
@with_current_tenant_id
@@ -7,12 +7,12 @@ from pydantic import BaseModel, Field, field_validator
from sqlalchemy.orm import Session
from controllers.common.fields import SimpleResultResponse, ValidationResultResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.common.session import with_session
from controllers.console import console_ns
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
is_admin_or_owner_required,
model_validate,
@@ -208,7 +208,7 @@ class ModelProviderCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCredentialId)
@@ -226,7 +226,7 @@ class ModelProviderCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_CREATE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_CREATE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCredentialCreate)
@@ -250,7 +250,7 @@ class ModelProviderCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCredentialUpdate)
@@ -275,7 +275,7 @@ class ModelProviderCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCredentialDelete)
@@ -295,7 +295,7 @@ class ModelProviderCredentialSwitchApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_USE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_USE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCredentialSwitch)
@@ -372,7 +372,7 @@ class PreferredProviderTypeUpdateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_USE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_USE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserPreferredProviderType)
+11 -11
View File
@@ -5,6 +5,7 @@ from flask_restx import Resource
from pydantic import BaseModel, Field, field_validator
from controllers.common.fields import SimpleResultResponse, ValidationResultResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import (
query_params_from_model,
register_enum_models,
@@ -14,7 +15,6 @@ from controllers.common.schema import (
from controllers.console import console_ns
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
is_admin_or_owner_required,
model_validate,
@@ -227,7 +227,7 @@ class DefaultModelApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserPostDefault)
@@ -276,7 +276,7 @@ class ModelProviderModelApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserPostModels)
@@ -325,7 +325,7 @@ class ModelProviderModelApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserDeleteModels)
@@ -350,7 +350,7 @@ class ModelProviderModelCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -413,7 +413,7 @@ class ModelProviderModelCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_CREATE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_CREATE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserCreateCredential)
@@ -446,7 +446,7 @@ class ModelProviderModelCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserUpdateCredential)
@@ -474,7 +474,7 @@ class ModelProviderModelCredentialApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserDeleteCredential)
@@ -499,7 +499,7 @@ class ModelProviderModelCredentialSwitchApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_USE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_USE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ParserSwitch)
@@ -526,7 +526,7 @@ class ModelProviderModelEnableApi(Resource):
@login_required
@account_initialization_required
@with_current_tenant_id
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@model_validate(ParserDeleteModels)
def patch(self, req_data: ParserDeleteModels, tenant_id: str, provider: str):
@@ -548,7 +548,7 @@ class ModelProviderModelDisableApi(Resource):
@login_required
@account_initialization_required
@with_current_tenant_id
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@model_validate(ParserDeleteModels)
def patch(self, req_data: ParserDeleteModels, tenant_id: str, provider: str):
+17 -17
View File
@@ -11,6 +11,7 @@ from werkzeug.exceptions import Forbidden
from configs import dify_config
from controllers.common.fields import BinaryFileResponse, SuccessResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import (
query_params_from_model,
register_enum_models,
@@ -21,7 +22,6 @@ from controllers.console import console_ns
from controllers.console.workspace import plugin_permission_required
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
is_admin_or_owner_required,
model_validate,
@@ -570,7 +570,7 @@ class PluginDebuggingKeyApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_DEBUG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_DEBUG, Workspace()))
@plugin_permission_required(debug_required=True)
@with_current_tenant_id
def get(self, tenant_id: str):
@@ -750,7 +750,7 @@ class PluginUploadFromPkgApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
def post(self, tenant_id: str):
@@ -771,7 +771,7 @@ class PluginUploadFromGithubApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserGithubUpload)
@@ -793,7 +793,7 @@ class PluginUploadFromBundleApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
def post(self, tenant_id: str):
@@ -814,7 +814,7 @@ class PluginInstallFromPkgApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserPluginIdentifiers)
@@ -835,7 +835,7 @@ class PluginInstallFromGithubApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserGithubInstall)
@@ -862,7 +862,7 @@ class PluginInstallFromMarketplaceApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserPluginIdentifiers)
@@ -883,7 +883,7 @@ class PluginFetchMarketplacePkgApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserPluginIdentifierQuery)
@@ -909,7 +909,7 @@ class PluginFetchManifestApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_INSTALL, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_INSTALL, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserPluginIdentifierQuery)
@@ -1014,7 +1014,7 @@ class PluginUpgradeFromMarketplaceApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserMarketplaceUpgrade)
@@ -1037,7 +1037,7 @@ class PluginUpgradeFromGithubApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserGithubUpgrade)
@@ -1065,7 +1065,7 @@ class PluginUninstallApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_DELETE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_DELETE, Workspace()))
@plugin_permission_required(install_required=True)
@with_current_tenant_id
@model_validate(ParserUninstall)
@@ -1138,7 +1138,7 @@ class PluginFetchDynamicSelectOptionsApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_MODEL_CONFIG, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_MODEL_CONFIG, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -1169,7 +1169,7 @@ class PluginFetchDynamicSelectOptionsWithCredentialsApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -1201,7 +1201,7 @@ class PluginChangeAutoUpgradeApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@with_current_user
@with_current_tenant_id
@model_validate(ParserAutoUpgradeChange)
@@ -1256,7 +1256,7 @@ class PluginAutoUpgradeExcludePluginApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@with_current_tenant_id
@model_validate(ParserExcludePlugin)
def post(self, req_data: ParserExcludePlugin, tenant_id: str):
+323 -379
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
from collections.abc import Callable, Mapping
from dataclasses import dataclass
from typing import Any, Literal
from flask import request
@@ -9,9 +11,10 @@ from sqlalchemy import select
from werkzeug.exceptions import NotFound
from configs import dify_config
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.console import console_ns
from controllers.console.wraps import RBACPermission, RBACResourceScope, model_validate, rbac_permission_required
from controllers.console.wraps import RBACPermission, model_validate, rbac_permission_required
from core.db.session_factory import session_factory
from enums import DeploymentEdition
from extensions.ext_database import db
@@ -50,6 +53,7 @@ register_response_schema_models(
svc.MyPermissionsResponse,
svc.AppAccessMatrix,
svc.DatasetAccessMatrix,
svc.AgentAccessMatrix,
svc.WorkspaceAccessMatrix,
svc.ResourceWhitelist,
svc.ResourceWhitelistConfig,
@@ -282,24 +286,6 @@ class RBACWorkspaceCatalogApi(Resource):
return _dump(svc.RBACService.Catalog.workspace(tenant_id, account_id))
@console_ns.route("/workspaces/current/rbac/role-permissions/catalog/app")
class RBACAppCatalogApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.PermissionCatalogResponse.__name__])
def get(self):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.Catalog.app(tenant_id, account_id))
@console_ns.route("/workspaces/current/rbac/role-permissions/catalog/dataset")
class RBACDatasetCatalogApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.PermissionCatalogResponse.__name__])
def get(self):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.Catalog.dataset(tenant_id, account_id))
# ---------------------------------------------------------------------------
# Roles.
# ---------------------------------------------------------------------------
@@ -323,9 +309,7 @@ class _RoleUpsertRequest(BaseModel):
@console_ns.route("/workspaces/current/rbac/roles")
class RBACRolesApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[_RBACRoleList.__name__])
@model_validate(_RolesListQuery)
def get(self, req_data: _RolesListQuery):
@@ -349,9 +333,7 @@ class RBACRolesApi(Resource):
return _dump(result)
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(201, "Role created", console_ns.models[svc.RBACRole.__name__])
def post(self):
tenant_id, account_id = _current_ids()
@@ -363,9 +345,7 @@ class RBACRolesApi(Resource):
@console_ns.route("/workspaces/current/rbac/roles/<uuid:role_id>")
class RBACRoleItemApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.RBACRole.__name__])
def get(self, role_id):
tenant_id, account_id = _current_ids()
@@ -379,9 +359,7 @@ class RBACRoleItemApi(Resource):
)
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.RBACRole.__name__])
def put(self, role_id):
tenant_id, account_id = _current_ids()
@@ -390,9 +368,7 @@ class RBACRoleItemApi(Resource):
return _dump(role)
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.RBACRole.__name__])
def delete(self, role_id):
tenant_id, account_id = _current_ids()
@@ -403,9 +379,7 @@ class RBACRoleItemApi(Resource):
@console_ns.route("/workspaces/current/rbac/roles/<uuid:role_id>/copy")
class RBACRoleCopyApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(201, "Role copied", console_ns.models[svc.RBACRole.__name__])
def post(self, role_id):
tenant_id, account_id = _current_ids()
@@ -430,9 +404,7 @@ class _AccessPolicyUpdateRequest(BaseModel):
@console_ns.route("/workspaces/current/rbac/access-policies")
class RBACAccessPoliciesApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[_AccessPolicyList.__name__])
def get(self):
tenant_id, account_id = _current_ids()
@@ -449,9 +421,7 @@ class RBACAccessPoliciesApi(Resource):
)
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(201, "Policy created", console_ns.models[svc.AccessPolicy.__name__])
def post(self):
tenant_id, account_id = _current_ids()
@@ -472,18 +442,14 @@ class RBACAccessPoliciesApi(Resource):
@console_ns.route("/workspaces/current/rbac/access-policies/<uuid:policy_id>")
class RBACAccessPolicyItemApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.AccessPolicy.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AccessPolicies.get(tenant_id, account_id, str(policy_id)))
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.AccessPolicy.__name__])
def put(self, policy_id):
tenant_id, account_id = _current_ids()
@@ -501,9 +467,7 @@ class RBACAccessPolicyItemApi(Resource):
return _dump(policy)
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.AccessPolicy.__name__])
def delete(self, policy_id):
tenant_id, account_id = _current_ids()
@@ -514,9 +478,7 @@ class RBACAccessPolicyItemApi(Resource):
@console_ns.route("/workspaces/current/rbac/access-policies/<uuid:policy_id>/copy")
class RBACAccessPolicyCopyApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(201, "Policy copied", console_ns.models[svc.AccessPolicy.__name__])
def post(self, policy_id):
tenant_id, account_id = _current_ids()
@@ -527,9 +489,7 @@ class RBACAccessPolicyCopyApi(Resource):
@console_ns.route("/workspaces/current/rbac/access-policy-bindings/<uuid:binding_id>/lock")
class RBACAccessPolicyBindingLockApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.AccessPolicyBindingState.__name__])
def put(self, binding_id):
tenant_id, account_id = _current_ids()
@@ -539,20 +499,13 @@ class RBACAccessPolicyBindingLockApi(Resource):
@console_ns.route("/workspaces/current/rbac/access-policy-bindings/<uuid:binding_id>/unlock")
class RBACAccessPolicyBindingUnlockApi(Resource):
@login_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.WORKSPACE_ROLE_MANAGE, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.WORKSPACE_ROLE_MANAGE, Workspace()))
@console_ns.response(200, "Success", console_ns.models[svc.AccessPolicyBindingState.__name__])
def put(self, binding_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AccessPolicyBindings.unlock(tenant_id, account_id, str(binding_id)))
# ---------------------------------------------------------------------------
# Per-app access (App Access Config).
# ---------------------------------------------------------------------------
class _ResourceAccessScopeRequest(BaseModel):
automatic_include_workspace_members: bool
@@ -611,346 +564,337 @@ class RBACMyPermissionsApi(Resource):
account_id,
app_id=request.args.get("app_id") or None,
dataset_id=request.args.get("dataset_id") or None,
agent_id=request.args.get("agent_id") or None,
session=db.session(),
)
)
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/access-policy")
class RBACAppMatrixApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_AccessControlLanguageQuery))
@console_ns.response(200, "Success", console_ns.models[svc.AppAccessMatrix.__name__])
def get(self, app_id):
tenant_id, account_id = _current_ids()
result = svc.RBACService.AppAccess.matrix(tenant_id, account_id, str(app_id))
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/whitelist")
class RBACAppWhitelistApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def get(self, app_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AppAccess.whitelist(tenant_id, account_id, str(app_id)))
@login_required
@console_ns.expect(console_ns.models[_ResourceAccessScopeRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def put(self, app_id):
tenant_id, account_id = _current_ids()
request = _payload(_ResourceAccessScopeRequest)
result = svc.RBACService.AppAccess.replace_whitelist(
tenant_id,
account_id,
str(app_id),
svc.ReplaceMemberBindings(automatic_include_workspace_members=request.automatic_include_workspace_members),
)
if request.automatic_include_workspace_members:
initialize_created_app_rbac_access_task.delay(tenant_id, account_id, app_id=str(app_id))
return _dump(result)
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/whitelist_config")
class RBACAppWhitelistConfigApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelistConfig.__name__])
def get(self, app_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AppAccess.whitelist_config(tenant_id, account_id, str(app_id)))
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/user-access-policies")
class RBACAppUserAccessPoliciesApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_ResourceUserAccessPoliciesQuery))
@console_ns.response(200, "Success", console_ns.models[svc.ResourceUserAccessPoliciesResponse.__name__])
def get(self, app_id):
tenant_id, account_id = _current_ids()
options = _pagination_options()
result = svc.RBACService.AppAccess.user_access_policies(tenant_id, account_id, str(app_id), options=options)
_move_resource_maintainer_first(result.data, svc.app_maintainer_id(tenant_id, str(app_id)))
_hydrate_resource_user_account_names(result.data)
return _dump(result)
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/users/<uuid:target_account_id>/access-policies")
class RBACAppUserAccessPolicyAssignmentApi(Resource):
@login_required
@console_ns.expect(console_ns.models[svc.ReplaceUserAccessPolicies.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ReplaceUserAccessPoliciesResponse.__name__])
def put(self, app_id, target_account_id):
tenant_id, account_id = _current_ids()
payload = _payload(svc.ReplaceUserAccessPolicies)
return _dump(
svc.RBACService.AppAccess.replace_user_access_policies(
tenant_id,
account_id,
app_id,
target_account_id,
payload,
)
)
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/access-policies/<uuid:policy_id>/role-bindings")
class RBACAppRoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, app_id, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AppAccess.list_role_bindings(tenant_id, account_id, str(app_id), str(policy_id)))
@console_ns.route("/workspaces/current/rbac/apps/<uuid:app_id>/access-policies/<string:policy_id>/member-bindings")
class RBACAppMemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, app_id, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.AppAccess.list_member_bindings(tenant_id, account_id, str(app_id), str(policy_id)))
@login_required
@console_ns.expect(console_ns.models[_DeleteMemberBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def delete(self, app_id, policy_id):
tenant_id, account_id = _current_ids()
request_body = _payload(_DeleteMemberBindingsRequest)
svc.RBACService.AppAccess.delete_member_bindings(
tenant_id,
account_id,
str(app_id),
str(policy_id),
svc.DeleteMemberBindings(account_ids=request_body.account_ids),
)
return {"result": "success"}
# ---------------------------------------------------------------------------
# Per-dataset access (Knowledge Base Access Config).
# ---------------------------------------------------------------------------
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/access-policy")
class RBACDatasetMatrixApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_AccessControlLanguageQuery))
@console_ns.response(200, "Success", console_ns.models[svc.DatasetAccessMatrix.__name__])
def get(self, dataset_id):
tenant_id, account_id = _current_ids()
result = svc.RBACService.DatasetAccess.matrix(tenant_id, account_id, str(dataset_id))
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/whitelist_config")
class RBACDatasetWhitelistConfigApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelistConfig.__name__])
def get(self, dataset_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.DatasetAccess.whitelist_config(tenant_id, account_id, str(dataset_id)))
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/whitelist")
class RBACDatasetWhitelistApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def get(self, dataset_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.DatasetAccess.whitelist(tenant_id, account_id, str(dataset_id)))
@login_required
@console_ns.expect(console_ns.models[_ResourceAccessScopeRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def put(self, dataset_id):
tenant_id, account_id = _current_ids()
request = _payload(_ResourceAccessScopeRequest)
result = svc.RBACService.DatasetAccess.replace_whitelist(
tenant_id,
account_id,
str(dataset_id),
svc.ReplaceMemberBindings(automatic_include_workspace_members=request.automatic_include_workspace_members),
)
# Widening the scope only records it: the members still need the default access policy
# before they can reach the dataset, same as the app whitelist route above.
if request.automatic_include_workspace_members:
initialize_created_app_rbac_access_task.delay(tenant_id, account_id, dataset_id=str(dataset_id))
return _dump(result)
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/user-access-policies")
class RBACDatasetUserAccessPoliciesApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_ResourceUserAccessPoliciesQuery))
@console_ns.response(200, "Success", console_ns.models[svc.ResourceUserAccessPoliciesResponse.__name__])
def get(self, dataset_id):
tenant_id, account_id = _current_ids()
options = _pagination_options()
result = svc.RBACService.DatasetAccess.user_access_policies(
tenant_id, account_id, str(dataset_id), options=options
)
_move_resource_maintainer_first(result.data, svc.dataset_maintainer_id(tenant_id, str(dataset_id)))
_hydrate_resource_user_account_names(result.data)
return _dump(result)
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/users/<uuid:target_account_id>/access-policies")
class RBACDatasetUserAccessPolicyAssignmentApi(Resource):
@login_required
@console_ns.expect(console_ns.models[svc.ReplaceUserAccessPolicies.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ReplaceUserAccessPoliciesResponse.__name__])
def put(self, dataset_id, target_account_id):
tenant_id, account_id = _current_ids()
payload = _payload(svc.ReplaceUserAccessPolicies)
return _dump(
svc.RBACService.DatasetAccess.replace_user_access_policies(
tenant_id,
account_id,
str(dataset_id),
str(target_account_id),
payload,
)
)
@console_ns.route("/workspaces/current/rbac/datasets/<uuid:dataset_id>/access-policies/<uuid:policy_id>/role-bindings")
class RBACDatasetRoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, dataset_id, policy_id):
tenant_id, account_id = _current_ids()
return _dump(
svc.RBACService.DatasetAccess.list_role_bindings(tenant_id, account_id, str(dataset_id), str(policy_id))
)
@console_ns.route(
"/workspaces/current/rbac/datasets/<uuid:dataset_id>/access-policies/<string:policy_id>/member-bindings"
type _ResourceAccessClient = (
type[svc.RBACService.AppAccess] | type[svc.RBACService.DatasetAccess] | type[svc.RBACService.AgentAccess]
)
class RBACDatasetMemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, dataset_id, policy_id):
tenant_id, account_id = _current_ids()
return _dump(
svc.RBACService.DatasetAccess.list_member_bindings(tenant_id, account_id, str(dataset_id), str(policy_id))
)
@login_required
@console_ns.expect(console_ns.models[_DeleteMemberBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def delete(self, dataset_id, policy_id):
tenant_id, account_id = _current_ids()
request_body = _payload(_DeleteMemberBindingsRequest)
svc.RBACService.DatasetAccess.delete_member_bindings(
tenant_id,
account_id,
str(dataset_id),
str(policy_id),
svc.DeleteMemberBindings(account_ids=request_body.account_ids),
)
return {"result": "success"}
@console_ns.route("/workspaces/current/rbac/workspace/apps/access-policy")
class RBACWorkspaceAppMatrixApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.WorkspaceAccessMatrix.__name__])
def get(self):
tenant_id, account_id = _current_ids()
options = _pagination_options()
result = svc.RBACService.WorkspaceAccess.app_matrix(tenant_id, account_id, options=options)
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
@dataclass(frozen=True)
class _ResourceAccessRoutes:
resource_type: svc.RBACResourceType
class_prefix: str
matrix_model: type[BaseModel]
access: _ResourceAccessClient
catalog: Callable[[str, str], svc.PermissionCatalogResponse]
workspace_matrix: Callable[[str, str, svc.ListOption], svc.WorkspaceAccessMatrix]
workspace_role_bindings: Callable[[str, str, str], svc.RoleBindingsResponse]
workspace_member_bindings: Callable[[str, str, str], svc.MemberBindingsResponse]
replace_workspace_bindings: Callable[[str, str, str, svc.ReplaceBindings], svc.AccessMatrixItem]
maintainer_id: Callable[[str, str], str | None] | None = None
@property
def url_segment(self) -> str:
return self.resource_type.route.segment
@property
def id_param(self) -> str:
return self.resource_type.route.id_param
@console_ns.route("/workspaces/current/rbac/workspace/apps/access-policies/<uuid:policy_id>/role-bindings")
class RBACWorkspaceAppRoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.WorkspaceAccess.list_app_role_bindings(tenant_id, account_id, str(policy_id)))
@dataclass(frozen=True)
class _ResourceAccessApis:
catalog: type[Resource]
matrix: type[Resource]
whitelist: type[Resource]
whitelist_config: type[Resource]
user_access_policies: type[Resource]
user_access_policy_assignment: type[Resource]
role_bindings: type[Resource]
member_bindings: type[Resource]
workspace_matrix: type[Resource]
workspace_role_bindings: type[Resource]
workspace_bindings: type[Resource]
workspace_member_bindings: type[Resource]
@console_ns.route("/workspaces/current/rbac/workspace/apps/access-policies/<uuid:policy_id>/bindings")
class RBACWorkspaceAppBindingsApi(Resource):
@login_required
@console_ns.expect(console_ns.models[_ReplaceBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.AccessMatrixItem.__name__])
def put(self, policy_id):
tenant_id, account_id = _current_ids()
request = _payload(_ReplaceBindingsRequest)
return _dump(
svc.RBACService.WorkspaceAccess.replace_app_bindings(
_RESOURCE_ACCESS_ROUTES = (
_ResourceAccessRoutes(
resource_type=svc.RBACResourceType.APP,
class_prefix="App",
matrix_model=svc.AppAccessMatrix,
access=svc.RBACService.AppAccess,
catalog=lambda tenant_id, account_id: svc.RBACService.Catalog.app(tenant_id, account_id),
workspace_matrix=lambda tenant_id, account_id, options: svc.RBACService.WorkspaceAccess.app_matrix(
tenant_id, account_id, options=options
),
workspace_role_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_app_role_bindings(tenant_id, account_id, policy_id)
),
workspace_member_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_app_member_bindings(tenant_id, account_id, policy_id)
),
replace_workspace_bindings=lambda tenant_id, account_id, policy_id, payload: (
svc.RBACService.WorkspaceAccess.replace_app_bindings(tenant_id, account_id, policy_id, payload)
),
maintainer_id=lambda tenant_id, resource_id: svc.app_maintainer_id(tenant_id, resource_id),
),
_ResourceAccessRoutes(
resource_type=svc.RBACResourceType.DATASET,
class_prefix="Dataset",
matrix_model=svc.DatasetAccessMatrix,
access=svc.RBACService.DatasetAccess,
catalog=lambda tenant_id, account_id: svc.RBACService.Catalog.dataset(tenant_id, account_id),
workspace_matrix=lambda tenant_id, account_id, options: svc.RBACService.WorkspaceAccess.dataset_matrix(
tenant_id, account_id, options=options
),
workspace_role_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_dataset_role_bindings(tenant_id, account_id, policy_id)
),
workspace_member_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_dataset_member_bindings(tenant_id, account_id, policy_id)
),
replace_workspace_bindings=lambda tenant_id, account_id, policy_id, payload: (
svc.RBACService.WorkspaceAccess.replace_dataset_bindings(tenant_id, account_id, policy_id, payload)
),
maintainer_id=lambda tenant_id, resource_id: svc.dataset_maintainer_id(tenant_id, resource_id),
),
_ResourceAccessRoutes(
resource_type=svc.RBACResourceType.AGENT,
class_prefix="Agent",
matrix_model=svc.AgentAccessMatrix,
access=svc.RBACService.AgentAccess,
catalog=lambda tenant_id, account_id: svc.RBACService.Catalog.agent(tenant_id, account_id),
workspace_matrix=lambda tenant_id, account_id, options: svc.RBACService.WorkspaceAccess.agent_matrix(
tenant_id, account_id, options=options
),
workspace_role_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_agent_role_bindings(tenant_id, account_id, policy_id)
),
workspace_member_bindings=lambda tenant_id, account_id, policy_id: (
svc.RBACService.WorkspaceAccess.list_agent_member_bindings(tenant_id, account_id, policy_id)
),
replace_workspace_bindings=lambda tenant_id, account_id, policy_id, payload: (
svc.RBACService.WorkspaceAccess.replace_agent_bindings(tenant_id, account_id, policy_id, payload)
),
),
)
def _build_resource_access_apis(spec: _ResourceAccessRoutes) -> _ResourceAccessApis:
id_param = spec.id_param
resource_prefix = f"/workspaces/current/rbac/{spec.url_segment}/<uuid:{id_param}>"
workspace_prefix = f"/workspaces/current/rbac/workspace/{spec.url_segment}"
def resource_id(path_params: Mapping[str, object]) -> str:
return str(path_params[id_param])
def register(resource: type[Resource], name: str, url: str) -> type[Resource]:
resource.__name__ = name
resource.__qualname__ = name
console_ns.route(url)(resource)
return resource
class CatalogApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.PermissionCatalogResponse.__name__])
def get(self):
tenant_id, account_id = _current_ids()
return _dump(spec.catalog(tenant_id, account_id))
class MatrixApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_AccessControlLanguageQuery))
@console_ns.response(200, "Success", console_ns.models[spec.matrix_model.__name__])
def get(self, **path_params):
tenant_id, account_id = _current_ids()
result = spec.access.matrix(tenant_id, account_id, resource_id(path_params))
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
class WhitelistApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def get(self, **path_params):
tenant_id, account_id = _current_ids()
return _dump(spec.access.whitelist(tenant_id, account_id, resource_id(path_params)))
@login_required
@console_ns.expect(console_ns.models[_ResourceAccessScopeRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelist.__name__])
def put(self, **path_params):
tenant_id, account_id = _current_ids()
target_id = resource_id(path_params)
scope = _payload(_ResourceAccessScopeRequest)
result = spec.access.replace_whitelist(
tenant_id,
account_id,
str(policy_id),
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
target_id,
svc.ReplaceMemberBindings(
automatic_include_workspace_members=scope.automatic_include_workspace_members
),
)
)
if scope.automatic_include_workspace_members:
initialize_created_app_rbac_access_task.delay(tenant_id, account_id, **{id_param: target_id})
return _dump(result)
class WhitelistConfigApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.ResourceWhitelistConfig.__name__])
def get(self, **path_params):
tenant_id, account_id = _current_ids()
return _dump(spec.access.whitelist_config(tenant_id, account_id, resource_id(path_params)))
@console_ns.route("/workspaces/current/rbac/workspace/apps/access-policies/<uuid:policy_id>/member-bindings")
class RBACWorkspaceAppMemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.WorkspaceAccess.list_app_member_bindings(tenant_id, account_id, str(policy_id)))
class UserAccessPoliciesApi(Resource):
@login_required
@console_ns.doc(params=query_params_from_model(_ResourceUserAccessPoliciesQuery))
@console_ns.response(200, "Success", console_ns.models[svc.ResourceUserAccessPoliciesResponse.__name__])
def get(self, **path_params):
tenant_id, account_id = _current_ids()
target_id = resource_id(path_params)
options = _pagination_options()
result = spec.access.user_access_policies(tenant_id, account_id, target_id, options=options)
maintainer_id = spec.maintainer_id(tenant_id, target_id) if spec.maintainer_id else None
_move_resource_maintainer_first(result.data, maintainer_id)
_hydrate_resource_user_account_names(result.data)
return _dump(result)
class UserAccessPolicyAssignmentApi(Resource):
@login_required
@console_ns.expect(console_ns.models[svc.ReplaceUserAccessPolicies.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.ReplaceUserAccessPoliciesResponse.__name__])
def put(self, target_account_id, **path_params):
tenant_id, account_id = _current_ids()
payload = _payload(svc.ReplaceUserAccessPolicies)
return _dump(
spec.access.replace_user_access_policies(
tenant_id,
account_id,
resource_id(path_params),
str(target_account_id),
payload,
)
)
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policy")
class RBACWorkspaceDatasetMatrixApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.WorkspaceAccessMatrix.__name__])
def get(self):
tenant_id, account_id = _current_ids()
options = _pagination_options()
result = svc.RBACService.WorkspaceAccess.dataset_matrix(tenant_id, account_id, options=options)
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
class RoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, policy_id, **path_params):
tenant_id, account_id = _current_ids()
return _dump(
spec.access.list_role_bindings(tenant_id, account_id, resource_id(path_params), str(policy_id))
)
class MemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, policy_id, **path_params):
tenant_id, account_id = _current_ids()
return _dump(
spec.access.list_member_bindings(tenant_id, account_id, resource_id(path_params), str(policy_id))
)
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policies/<uuid:policy_id>/role-bindings")
class RBACWorkspaceDatasetRoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(svc.RBACService.WorkspaceAccess.list_dataset_role_bindings(tenant_id, account_id, str(policy_id)))
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policies/<uuid:policy_id>/bindings")
class RBACWorkspaceDatasetBindingsApi(Resource):
@login_required
@console_ns.expect(console_ns.models[_ReplaceBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.AccessMatrixItem.__name__])
def put(self, policy_id):
tenant_id, account_id = _current_ids()
request = _payload(_ReplaceBindingsRequest)
return _dump(
svc.RBACService.WorkspaceAccess.replace_dataset_bindings(
@login_required
@console_ns.expect(console_ns.models[_DeleteMemberBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def delete(self, policy_id, **path_params):
tenant_id, account_id = _current_ids()
body = _payload(_DeleteMemberBindingsRequest)
spec.access.delete_member_bindings(
tenant_id,
account_id,
resource_id(path_params),
str(policy_id),
svc.ReplaceBindings(role_ids=list(request.role_ids), account_ids=list(request.account_ids)),
svc.DeleteMemberBindings(account_ids=body.account_ids),
)
)
return {"result": "success"}
class WorkspaceMatrixApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.WorkspaceAccessMatrix.__name__])
def get(self):
tenant_id, account_id = _current_ids()
result = spec.workspace_matrix(tenant_id, account_id, _pagination_options())
_hydrate_access_matrix_account_names(result.items)
return _dump(result)
class WorkspaceRoleBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.RoleBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(spec.workspace_role_bindings(tenant_id, account_id, str(policy_id)))
class WorkspaceBindingsApi(Resource):
@login_required
@console_ns.expect(console_ns.models[_ReplaceBindingsRequest.__name__])
@console_ns.response(200, "Success", console_ns.models[svc.AccessMatrixItem.__name__])
def put(self, policy_id):
tenant_id, account_id = _current_ids()
body = _payload(_ReplaceBindingsRequest)
return _dump(
spec.replace_workspace_bindings(
tenant_id,
account_id,
str(policy_id),
svc.ReplaceBindings(role_ids=list(body.role_ids), account_ids=list(body.account_ids)),
)
)
class WorkspaceMemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(spec.workspace_member_bindings(tenant_id, account_id, str(policy_id)))
prefix = spec.class_prefix
return _ResourceAccessApis(
catalog=register(
CatalogApi,
f"RBAC{prefix}CatalogApi",
f"/workspaces/current/rbac/role-permissions/catalog/{spec.resource_type.value}",
),
matrix=register(MatrixApi, f"RBAC{prefix}MatrixApi", f"{resource_prefix}/access-policy"),
whitelist=register(WhitelistApi, f"RBAC{prefix}WhitelistApi", f"{resource_prefix}/whitelist"),
whitelist_config=register(
WhitelistConfigApi, f"RBAC{prefix}WhitelistConfigApi", f"{resource_prefix}/whitelist_config"
),
user_access_policies=register(
UserAccessPoliciesApi, f"RBAC{prefix}UserAccessPoliciesApi", f"{resource_prefix}/user-access-policies"
),
user_access_policy_assignment=register(
UserAccessPolicyAssignmentApi,
f"RBAC{prefix}UserAccessPolicyAssignmentApi",
f"{resource_prefix}/users/<uuid:target_account_id>/access-policies",
),
role_bindings=register(
RoleBindingsApi,
f"RBAC{prefix}RoleBindingsApi",
f"{resource_prefix}/access-policies/<uuid:policy_id>/role-bindings",
),
member_bindings=register(
MemberBindingsApi,
f"RBAC{prefix}MemberBindingsApi",
f"{resource_prefix}/access-policies/<string:policy_id>/member-bindings",
),
workspace_matrix=register(
WorkspaceMatrixApi, f"RBACWorkspace{prefix}MatrixApi", f"{workspace_prefix}/access-policy"
),
workspace_role_bindings=register(
WorkspaceRoleBindingsApi,
f"RBACWorkspace{prefix}RoleBindingsApi",
f"{workspace_prefix}/access-policies/<uuid:policy_id>/role-bindings",
),
workspace_bindings=register(
WorkspaceBindingsApi,
f"RBACWorkspace{prefix}BindingsApi",
f"{workspace_prefix}/access-policies/<uuid:policy_id>/bindings",
),
workspace_member_bindings=register(
WorkspaceMemberBindingsApi,
f"RBACWorkspace{prefix}MemberBindingsApi",
f"{workspace_prefix}/access-policies/<uuid:policy_id>/member-bindings",
),
)
@console_ns.route("/workspaces/current/rbac/workspace/datasets/access-policies/<uuid:policy_id>/member-bindings")
class RBACWorkspaceDatasetMemberBindingsApi(Resource):
@login_required
@console_ns.response(200, "Success", console_ns.models[svc.MemberBindingsResponse.__name__])
def get(self, policy_id):
tenant_id, account_id = _current_ids()
return _dump(
svc.RBACService.WorkspaceAccess.list_dataset_member_bindings(tenant_id, account_id, str(policy_id))
)
_RESOURCE_ACCESS_APIS = {spec.resource_type: _build_resource_access_apis(spec) for spec in _RESOURCE_ACCESS_ROUTES}
# ---------------------------------------------------------------------------
+11 -31
View File
@@ -10,13 +10,13 @@ from pydantic import BaseModel, ConfigDict, Field, ValidationError
from sqlalchemy.orm import Session
from controllers.common.fields import BinaryFileResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models
from controllers.common.session import with_session
from controllers.console import console_ns
from controllers.console.flask_admission import console_account_admission
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
edit_permission_required,
)
from fields.base import ResponseModel
@@ -298,9 +298,7 @@ class WorkspaceSkillsApi(Resource):
@console_ns.doc(params=query_params_from_model(WorkspaceSkillsQuery))
@console_ns.response(200, "Workspace skills", console_ns.models[SkillListResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_VIEW,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_VIEW, Workspace())],
)
@with_session(write=False)
def get(self, session: Session, request_context: RequestContext):
@@ -325,9 +323,7 @@ class WorkspaceSkillsApi(Resource):
@console_ns.expect(console_ns.models[SkillCreatePayload.__name__])
@console_ns.response(201, "Skill created", console_ns.models[SkillDetailResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_EDIT,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_EDIT, Workspace())],
)
@edit_permission_required
@with_session
@@ -391,9 +387,7 @@ class WorkspaceSkillImportApi(Resource):
@console_ns.doc(description="Import a Skill zip package from multipart form field `file`.")
@console_ns.response(201, "Skill imported", console_ns.models[SkillDetailResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_EDIT,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_EDIT, Workspace())],
)
@edit_permission_required
@with_session
@@ -419,9 +413,7 @@ class WorkspaceSkillImportApi(Resource):
class WorkspaceSkillApi(Resource):
@console_ns.response(200, "Skill detail", console_ns.models[SkillDetailResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_VIEW,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_VIEW, Workspace())],
)
@with_session(write=False)
def get(self, session: Session, request_context: RequestContext, skill_id: str):
@@ -436,9 +428,7 @@ class WorkspaceSkillApi(Resource):
@console_ns.expect(console_ns.models[SkillMetadataPayload.__name__])
@console_ns.response(200, "Skill updated", console_ns.models[SkillResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_EDIT,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_EDIT, Workspace())],
)
@edit_permission_required
@with_session
@@ -462,9 +452,7 @@ class WorkspaceSkillApi(Resource):
@console_ns.expect(console_ns.models[SkillDeletePayload.__name__])
@console_ns.response(200, "Skill deleted", console_ns.models[SkillDeleteResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_DELETE,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_DELETE, Workspace())],
)
@edit_permission_required
@with_session
@@ -487,9 +475,7 @@ class WorkspaceSkillApi(Resource):
class WorkspaceSkillDuplicateApi(Resource):
@console_ns.response(201, "Skill duplicated", console_ns.models[SkillDetailResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_EDIT,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_EDIT, Workspace())],
)
@edit_permission_required
@with_session
@@ -509,9 +495,7 @@ class WorkspaceSkillDuplicateApi(Resource):
class WorkspaceSkillExportApi(Resource):
@console_ns.response(200, "Published Skill zip archive")
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_VIEW,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_VIEW, Workspace())],
)
@with_session(write=False)
def get(self, session: Session, request_context: RequestContext, skill_id: str):
@@ -696,9 +680,7 @@ class WorkspaceSkillPublishApi(Resource):
@console_ns.expect(console_ns.models[SkillPublishPayload.__name__])
@console_ns.response(200, "Skill published", console_ns.models[SkillVersionResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_PUBLISH,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_PUBLISH, Workspace())],
)
@edit_permission_required
@with_session
@@ -723,9 +705,7 @@ class WorkspaceSkillRestoreApi(Resource):
@console_ns.expect(console_ns.models[SkillRestorePayload.__name__])
@console_ns.response(200, "Skill version restored to draft", console_ns.models[SkillDetailResponse.__name__])
@console_account_admission(
rbac_resource_scope=RBACResourceScope.WORKSPACE,
rbac_permission=RBACPermission.SKILL_PUBLISH,
rbac_resource_required=False,
rbac_checks=[RBACCheck(RBACPermission.SKILL_PUBLISH, Workspace())],
)
@edit_permission_required
@with_session
+8 -20
View File
@@ -8,6 +8,7 @@ from sqlalchemy.orm import Session, sessionmaker
from werkzeug.exceptions import NotFound
from controllers.common.fields import TextFileResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import (
query_params_from_model,
register_response_schema_models,
@@ -24,7 +25,6 @@ from controllers.console.snippets.payloads import (
)
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
edit_permission_required,
model_validate,
@@ -147,9 +147,7 @@ class CustomizedSnippetsApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_user
@with_current_tenant_id
@model_validate(CreateSnippetPayload)
@@ -211,9 +209,7 @@ class CustomizedSnippetDetailApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_user
@with_current_tenant_id
@model_validate(UpdateSnippetPayload)
@@ -258,7 +254,7 @@ class CustomizedSnippetDetailApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_MANAGE, Workspace()))
@with_current_user
@with_current_tenant_id
def delete(self, current_tenant_id: str, current_user: Account, snippet_id: str):
@@ -296,9 +292,7 @@ class CustomizedSnippetExportApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_tenant_id
def get(self, current_tenant_id: str, snippet_id: str):
"""Export snippet as DSL."""
@@ -351,9 +345,7 @@ class CustomizedSnippetImportApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_user
@with_session
@model_validate(SnippetImportPayload)
@@ -390,9 +382,7 @@ class CustomizedSnippetImportConfirmApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_user
@with_session
def post(self, session: Session, current_user: Account, import_id: str):
@@ -420,9 +410,7 @@ class CustomizedSnippetCheckDependenciesApi(Resource):
@login_required
@account_initialization_required
@edit_permission_required
@rbac_permission_required(
RBACResourceScope.WORKSPACE, RBACPermission.SNIPPETS_CREATE_AND_MODIFY, resource_required=False
)
@rbac_permission_required(RBACCheck(RBACPermission.SNIPPETS_CREATE_AND_MODIFY, Workspace()))
@with_current_tenant_id
def get(self, current_tenant_id: str, snippet_id: str):
"""Check dependencies for a snippet."""
@@ -20,6 +20,7 @@ from werkzeug.exceptions import Forbidden
from configs import dify_config
from controllers.common.fields import SimpleResultResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import (
query_params_from_model,
query_params_from_request,
@@ -29,7 +30,6 @@ from controllers.common.schema import (
from controllers.console import console_ns
from controllers.console.wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
enterprise_license_required,
is_admin_or_owner_required,
@@ -563,7 +563,7 @@ class ToolBuiltinProviderDeleteApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(BuiltinToolCredentialDeletePayload)
@@ -590,7 +590,7 @@ class ToolBuiltinProviderAddApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_CREATE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_CREATE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -621,7 +621,7 @@ class ToolBuiltinProviderUpdateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -689,7 +689,7 @@ class ToolApiProviderAddApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -769,7 +769,7 @@ class ToolApiProviderUpdateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -800,7 +800,7 @@ class ToolApiProviderDeleteApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -908,7 +908,7 @@ class ToolWorkflowProviderCreateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -938,7 +938,7 @@ class ToolWorkflowProviderUpdateApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -968,7 +968,7 @@ class ToolWorkflowProviderDeleteApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.TOOL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.TOOL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -1125,7 +1125,7 @@ class ToolPluginOAuthApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -1251,7 +1251,7 @@ class ToolBuiltinProviderSetDefaultApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_USE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_USE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(BuiltinProviderDefaultCredentialPayload)
@@ -1273,7 +1273,7 @@ class ToolOAuthCustomClient(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(ToolOAuthCustomClientPayload)
@@ -1297,7 +1297,7 @@ class ToolOAuthCustomClient(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
def get(self, current_tenant_id: str, provider: str):
@@ -1309,7 +1309,7 @@ class ToolOAuthCustomClient(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_tenant_id
def delete(self, current_tenant_id: str, provider: str):
@@ -1379,7 +1379,7 @@ class ToolProviderMCPApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.MCP_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.MCP_MANAGE, Workspace()))
@with_current_user
@with_current_tenant_id
@model_validate(MCPProviderCreatePayload)
@@ -1433,7 +1433,7 @@ class ToolProviderMCPApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.MCP_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.MCP_MANAGE, Workspace()))
@with_current_tenant_id
@model_validate(MCPProviderUpdatePayload)
def put(self, req_data: MCPProviderUpdatePayload, current_tenant_id: str):
@@ -1487,7 +1487,7 @@ class ToolProviderMCPApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.MCP_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.MCP_MANAGE, Workspace()))
@with_current_tenant_id
@model_validate(MCPProviderDeletePayload)
def delete(self, req_data: MCPProviderDeletePayload, current_tenant_id: str):
@@ -1505,7 +1505,7 @@ class ToolMCPAuthApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.MCP_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.MCP_MANAGE, Workspace()))
@with_current_tenant_id
@model_validate(MCPAuthPayload)
def post(self, req_data: MCPAuthPayload, tenant_id: str):
@@ -1617,7 +1617,7 @@ class ToolMCPUpdateApi(Resource):
@setup_required
@login_required
@account_initialization_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.MCP_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.MCP_MANAGE, Workspace()))
@with_current_tenant_id
def get(self, tenant_id: str, provider_id: str):
with sessionmaker(db.engine).begin() as session:
@@ -10,6 +10,7 @@ from werkzeug.exceptions import BadRequest, Forbidden
from configs import dify_config
from controllers.common.errors import NotFoundError
from controllers.common.fields import SimpleResultResponse
from controllers.common.rbac import RBACCheck, Workspace
from controllers.common.schema import register_response_schema_models, register_schema_models
from core.entities.provider_entities import ProviderConfig
from core.plugin.entities.plugin_daemon import CredentialType
@@ -35,7 +36,6 @@ from services.trigger.trigger_subscription_operator_service import TriggerSubscr
from .. import console_ns
from ..wraps import (
RBACPermission,
RBACResourceScope,
account_initialization_required,
edit_permission_required,
is_admin_or_owner_required,
@@ -199,7 +199,7 @@ class TriggerSubscriptionListApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -235,7 +235,7 @@ class TriggerSubscriptionBuilderCreateApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -271,7 +271,7 @@ class TriggerSubscriptionBuilderGetApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -299,7 +299,7 @@ class TriggerSubscriptionBuilderVerifyApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -344,7 +344,7 @@ class TriggerSubscriptionBuilderUpdateApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.CREDENTIAL_MANAGE, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.CREDENTIAL_MANAGE, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -389,7 +389,7 @@ class TriggerSubscriptionBuilderLogsApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -420,7 +420,7 @@ class TriggerSubscriptionBuilderBuildApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id
@@ -464,7 +464,7 @@ class TriggerSubscriptionUpdateApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(TriggerSubscriptionBuilderUpdatePayload)
@@ -524,7 +524,7 @@ class TriggerSubscriptionDeleteApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
def post(self, tenant_id: str, subscription_id: str):
@@ -716,7 +716,7 @@ class TriggerOAuthClientManageApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
def get(self, tenant_id: str, provider: str):
@@ -763,7 +763,7 @@ class TriggerOAuthClientManageApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
@model_validate(TriggerOAuthClientPayload)
@@ -792,7 +792,7 @@ class TriggerOAuthClientManageApi(Resource):
@setup_required
@login_required
@is_admin_or_owner_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_tenant_id
def delete(self, tenant_id: str, provider: str):
@@ -826,7 +826,7 @@ class TriggerSubscriptionVerifyApi(Resource):
@setup_required
@login_required
@edit_permission_required
@rbac_permission_required(RBACResourceScope.WORKSPACE, RBACPermission.PLUGIN_PREFERENCES, resource_required=False)
@rbac_permission_required(RBACCheck(RBACPermission.PLUGIN_PREFERENCES, Workspace()))
@account_initialization_required
@with_current_user
@with_current_tenant_id