mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-31 04:45:23 +08:00
fix(api): harden facade fallbacks and secret permissions
This commit is contained in:
@@ -83,6 +83,12 @@ class ApplicationAPI:
|
||||
include_secret: bool = False,
|
||||
) -> list[dict]:
|
||||
self._authorize(context, 'pipeline.list')
|
||||
# Secret-bearing pipeline configuration must never be exposed merely
|
||||
# because a caller supplied ``include_secret=True``. The HTTP route
|
||||
# derives this flag from the same permission, but MCP/assistant callers
|
||||
# can invoke the facade directly.
|
||||
if include_secret:
|
||||
require_permission(context, Permission.RESOURCE_MANAGE)
|
||||
return await self.ap.pipeline_service.get_pipelines(
|
||||
context,
|
||||
sort_by,
|
||||
@@ -98,6 +104,8 @@ class ApplicationAPI:
|
||||
include_secret: bool = False,
|
||||
) -> dict | None:
|
||||
self._authorize(context, 'pipeline.get')
|
||||
if include_secret:
|
||||
require_permission(context, Permission.RESOURCE_MANAGE)
|
||||
return await self.ap.pipeline_service.get_pipeline(
|
||||
context,
|
||||
pipeline_uuid,
|
||||
@@ -106,7 +114,61 @@ class ApplicationAPI:
|
||||
|
||||
async def get_pipeline_extensions(self, context: RequestContext, pipeline_uuid: str) -> dict:
|
||||
self._authorize(context, 'pipeline.extensions.get')
|
||||
return await self.ap.pipeline_service.get_pipeline_extensions(context, pipeline_uuid)
|
||||
getter = getattr(self.ap.pipeline_service, 'get_pipeline_extensions', None)
|
||||
if callable(getter):
|
||||
return await getter(context, pipeline_uuid)
|
||||
|
||||
# Compatibility path for lightweight service doubles and older service
|
||||
# graphs. The production PipelineService owns this implementation;
|
||||
# this fallback keeps the shared facade usable while a graph is being
|
||||
# assembled and preserves its fail-closed normalization semantics.
|
||||
from ...pipeline.extension_preferences import normalize_extension_preferences
|
||||
from ..http.service.secrets import redact_secrets
|
||||
|
||||
pipeline = await self.ap.pipeline_service.get_pipeline(context, pipeline_uuid)
|
||||
if pipeline is None:
|
||||
return None
|
||||
connector = getattr(self.ap, 'plugin_connector', None)
|
||||
plugins = []
|
||||
if connector is not None:
|
||||
if getattr(connector, 'is_enable_plugin', False):
|
||||
require_context = getattr(connector, 'require_workspace_context', None)
|
||||
if callable(require_context):
|
||||
await require_context(context)
|
||||
list_plugins = getattr(connector, 'list_plugins', None)
|
||||
if callable(list_plugins):
|
||||
plugins = await list_plugins(component_kinds=['Command', 'EventListener', 'Tool'])
|
||||
skill_service = getattr(self.ap, 'skill_service', None)
|
||||
available_skills = []
|
||||
if skill_service is not None:
|
||||
try:
|
||||
available_skills = await skill_service.list_skills(context)
|
||||
except Exception as exc:
|
||||
logger = getattr(self.ap, 'logger', None)
|
||||
warning = getattr(logger, 'warning', None)
|
||||
if callable(warning):
|
||||
warning('Unable to list skills for pipeline extensions: %s', exc)
|
||||
mcp_service = getattr(self.ap, 'mcp_service', None)
|
||||
available_mcp_servers = []
|
||||
if mcp_service is not None:
|
||||
list_servers = getattr(mcp_service, 'get_mcp_servers', None)
|
||||
if callable(list_servers):
|
||||
available_mcp_servers = await list_servers(context, contain_runtime_info=True)
|
||||
prefs = normalize_extension_preferences(pipeline.get('extensions_preferences'))
|
||||
return {
|
||||
'enable_all_plugins': prefs.get('enable_all_plugins', True),
|
||||
'enable_all_mcp_servers': prefs.get('enable_all_mcp_servers', True),
|
||||
'enable_all_skills': prefs.get('enable_all_skills', True),
|
||||
'bound_plugins': prefs.get('plugins', []),
|
||||
'available_plugins': redact_secrets(plugins),
|
||||
'bound_mcp_servers': prefs.get('mcp_servers', []),
|
||||
'available_mcp_servers': available_mcp_servers,
|
||||
'bound_mcp_resources': prefs.get('mcp_resources', []),
|
||||
'mcp_resource_agent_read_enabled': prefs.get('mcp_resource_agent_read_enabled', True),
|
||||
'bound_skills': prefs.get('skills', []),
|
||||
'available_skills': available_skills,
|
||||
}
|
||||
|
||||
|
||||
async def update_pipeline_extensions(self, context: RequestContext, pipeline_uuid: str, **kwargs) -> None:
|
||||
self._authorize(context, 'pipeline.extensions.update')
|
||||
|
||||
Reference in New Issue
Block a user