mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-07-27 16:37:55 +00:00
* 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>
43 lines
1.5 KiB
Python
43 lines
1.5 KiB
Python
"""Shared Phase 1B authorization enforcement helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from collections.abc import Sequence
|
|
|
|
from langchain_core.tools import BaseTool
|
|
|
|
from deerflow.authz.provider import AuthorizationProvider, Principal
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def filter_tools_by_authorization(
|
|
tools: Sequence[BaseTool],
|
|
*,
|
|
provider: AuthorizationProvider | None,
|
|
principal: Principal,
|
|
fail_closed: bool,
|
|
) -> list[BaseTool]:
|
|
"""Return the policy-visible subset of *tools* without changing its order.
|
|
|
|
The caller must invoke this before deferred-tool assembly. Provider errors
|
|
and malformed filter results deny every tool when ``fail_closed`` is true;
|
|
an explicitly configured fail-open policy preserves the original set.
|
|
"""
|
|
original_tools = list(tools)
|
|
if provider is None:
|
|
return original_tools
|
|
|
|
candidates = [tool.name for tool in original_tools]
|
|
try:
|
|
allowed = provider.filter_resources(principal, "tool", candidates)
|
|
if not isinstance(allowed, list) or any(not isinstance(name, str) for name in allowed):
|
|
raise TypeError("AuthorizationProvider.filter_resources must return list[str]")
|
|
except Exception:
|
|
logger.exception("Authorization provider failed while filtering tools")
|
|
return [] if fail_closed else original_tools
|
|
|
|
allowed_names = set(allowed)
|
|
return [tool for tool in original_tools if tool.name in allowed_names]
|