hataa 7857fa0cce
feat(authz): enforce tool authorization at assembly and runtime (#4370)
* feat(authz): enforce tool authorization at assembly and runtime

* fix(middleware): guard deferred tool setup lookup (#4370)

---------

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
2026-07-23 22:51:35 +08:00

59 lines
2.3 KiB
Python

"""Provider factory — resolves and constructs the configured AuthorizationProvider.
This is the single entry point for creating an authorization provider from
``AuthorizationConfig``. It does not cache instances (Phase 1B resolves once
per agent build and passes the same instance to Layer 1 and Layer 2).
"""
from __future__ import annotations
from deerflow.authz.provider import AuthorizationProvider
from deerflow.config.authorization_config import AuthorizationConfig
from deerflow.reflection import resolve_variable
def resolve_authorization_provider(
config: AuthorizationConfig,
) -> AuthorizationProvider | None:
"""Resolve the authorization provider from config.
Returns:
A constructed ``AuthorizationProvider`` instance, or ``None`` if
authorization is disabled.
Raises:
ValueError: If ``enabled`` is True but no provider is configured,
or if the class path is invalid / construction fails / the
instance does not satisfy the ``AuthorizationProvider`` Protocol.
"""
if not config.enabled:
return None
if config.provider is None:
raise ValueError("authorization.enabled is true but no provider is configured; set authorization.provider.use to a class path")
class_path = config.provider.use
try:
provider_cls = resolve_variable(class_path, expected_type=type)
except (ImportError, ValueError) as err:
raise ValueError(f"Failed to resolve authorization provider class '{class_path}': {err}") from err
kwargs = dict(config.provider.config) if config.provider.config else {}
try:
instance = provider_cls(**kwargs)
except Exception as err:
raise ValueError(f"Failed to construct authorization provider '{class_path}': {err}") from err
if not isinstance(instance, AuthorizationProvider):
raise ValueError(f"Authorization provider '{class_path}' does not satisfy the AuthorizationProvider Protocol")
from deerflow.authz.rbac import RbacAuthorizationProvider
if isinstance(instance, RbacAuthorizationProvider):
try:
instance.validate_role(config.default_role, field="authorization.default_role")
except ValueError as err:
raise ValueError(f"Invalid authorization default_role for provider '{class_path}': {err}") from err
return instance