mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-12 15:09:47 +00:00
* fix(authz): recheck policy before sandbox reuse * fix(authz): avoid duplicate async sandbox checks * fix(authz): scope sandbox decision across middleware * fix(authz): construct async providers on the event loop * test(authz): avoid cold imports under Blockbuster --------- Co-authored-by: 嗜鵼 <hy2010hy2010@qq.com> Co-authored-by: PeaceMaker-best <221849497+PeaceMaker-best@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
65 lines
2.4 KiB
Python
65 lines
2.4 KiB
Python
"""Sandbox authorization resolution must stay off the async event loop."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from deerflow.authz import sandbox_authz
|
|
from deerflow.config.app_config import AppConfig
|
|
from deerflow.config.authorization_config import AuthorizationConfig, AuthorizationProviderConfig
|
|
from deerflow.config.model_config import ModelConfig
|
|
from deerflow.config.sandbox_config import SandboxConfig
|
|
from deerflow.sandbox import tools as sandbox_tools
|
|
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
async def test_reused_async_sandbox_offloads_config_and_provider_resolution(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Config hashing and class discovery stay off-loop; construction does not."""
|
|
probe = tmp_path / "sandbox-authz-probe"
|
|
await asyncio.to_thread(probe.write_text, "probe", encoding="utf-8")
|
|
|
|
app_config = AppConfig(
|
|
models=[ModelConfig(name="gpt-4", model="gpt-4", use="langchain_openai:ChatOpenAI")],
|
|
sandbox=SandboxConfig(use="deerflow.sandbox.local:LocalSandboxProvider"),
|
|
authorization=AuthorizationConfig(
|
|
enabled=True,
|
|
fail_closed=True,
|
|
default_role="user",
|
|
provider=AuthorizationProviderConfig(
|
|
use="deerflow.authz.rbac:RbacAuthorizationProvider",
|
|
config={"roles": {"user": {"sandbox": {"allow": "*"}}}},
|
|
),
|
|
),
|
|
)
|
|
|
|
def blocking_config_load():
|
|
probe.read_text(encoding="utf-8")
|
|
return app_config
|
|
|
|
discover_provider = sandbox_authz.resolve_authorization_provider_spec
|
|
|
|
def blocking_provider_discovery(config):
|
|
probe.read_text(encoding="utf-8")
|
|
return discover_provider(config)
|
|
|
|
monkeypatch.setattr(sandbox_authz, "safe_app_config", blocking_config_load)
|
|
monkeypatch.setattr(sandbox_authz, "resolve_authorization_provider_spec", blocking_provider_discovery)
|
|
|
|
sandbox = MagicMock()
|
|
sandbox_provider = MagicMock()
|
|
sandbox_provider.get.return_value = sandbox
|
|
monkeypatch.setattr(sandbox_tools, "get_sandbox_provider", lambda: sandbox_provider)
|
|
runtime = SimpleNamespace(
|
|
state={"sandbox": {"sandbox_id": "sbx-existing"}},
|
|
context={"thread_id": "t1", "user_id": "u1", "user_role": "user"},
|
|
config=None,
|
|
)
|
|
|
|
assert await sandbox_tools.ensure_sandbox_initialized_async(runtime) is sandbox
|