diff --git a/api/controllers/console/app/agent_app_sandbox.py b/api/controllers/console/app/agent_app_sandbox.py index c1d6c3f0f46..233fb977c29 100644 --- a/api/controllers/console/app/agent_app_sandbox.py +++ b/api/controllers/console/app/agent_app_sandbox.py @@ -24,8 +24,11 @@ from controllers.console import console_ns from controllers.console.app.error import AppNotFoundError from controllers.console.app.wraps import get_app_model from controllers.console.wraps import ( + RBACPermission, + RBACResourceScope, account_initialization_required, model_validate, + rbac_permission_required, setup_required, with_current_tenant_id, with_current_user, @@ -154,6 +157,7 @@ class AgentAppSandboxInfoResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @with_current_tenant_id @with_current_user def get(self, current_user: Account, tenant_id: str, agent_id: UUID): @@ -183,6 +187,7 @@ class AgentAppSandboxListResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @with_current_tenant_id @with_current_user def get(self, current_user: Account, tenant_id: str, agent_id: UUID): @@ -213,6 +218,7 @@ class AgentAppSandboxReadResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @with_current_tenant_id @with_current_user def get(self, current_user: Account, tenant_id: str, agent_id: UUID): @@ -243,6 +249,7 @@ class AgentAppSandboxDownloadResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @with_current_tenant_id @with_current_user @model_validate(AgentSandboxDownloadPayload) @@ -286,6 +293,7 @@ class WorkflowAgentSandboxListResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW]) @with_current_tenant_id def get(self, tenant_id: str, app_model: App, workflow_run_id: UUID, node_id: str): @@ -323,6 +331,7 @@ class WorkflowAgentSandboxReadResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW]) @with_current_tenant_id def get(self, tenant_id: str, app_model: App, workflow_run_id: UUID, node_id: str): @@ -353,6 +362,7 @@ class WorkflowAgentSandboxDownloadResource(Resource): @setup_required @login_required @account_initialization_required + @rbac_permission_required(RBACResourceScope.APP, RBACPermission.APP_VIEW_LAYOUT) @with_current_user @with_current_tenant_id @model_validate(WorkflowAgentSandboxDownloadPayload) diff --git a/api/tests/unit_tests/controllers/console/app/test_agent_app_sandbox.py b/api/tests/unit_tests/controllers/console/app/test_agent_app_sandbox.py index ed227fd09d6..c534cc346b3 100644 --- a/api/tests/unit_tests/controllers/console/app/test_agent_app_sandbox.py +++ b/api/tests/unit_tests/controllers/console/app/test_agent_app_sandbox.py @@ -1,7 +1,7 @@ from __future__ import annotations -from inspect import unwrap -from types import SimpleNamespace +from inspect import getclosurevars, unwrap +from types import FunctionType, SimpleNamespace import pytest from dify_agent.client import DifyAgentClientError, DifyAgentHTTPError, DifyAgentTimeoutError @@ -139,6 +139,27 @@ def _app_model(app_id: str = "app-1") -> App: ) +@pytest.mark.parametrize( + "method", + [ + module.AgentAppSandboxInfoResource.get, + module.AgentAppSandboxListResource.get, + module.AgentAppSandboxReadResource.get, + module.AgentAppSandboxDownloadResource.post, + module.WorkflowAgentSandboxListResource.get, + module.WorkflowAgentSandboxReadResource.get, + module.WorkflowAgentSandboxDownloadResource.post, + ], +) +def test_sandbox_resources_require_app_view_layout(method: FunctionType) -> None: + rbac_wrapper = unwrap(method, stop=lambda wrapper: "rbac_permission_required" in wrapper.__code__.co_qualname) + config = getclosurevars(rbac_wrapper).nonlocals + + assert config["resource_type"] == module.RBACResourceScope.APP + assert config["scene"] == module.RBACPermission.APP_VIEW_LAYOUT + assert config["resource_required"] is True + + def test_handle_maps_sandbox_and_agent_backend_errors() -> None: assert module._handle(AgentSandboxInspectorError("no_sandbox", "no sandbox", status_code=404)) == ( {"code": "no_sandbox", "message": "no sandbox"},