feat(agent): support cli tool scoped env (#37324)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
zyssyz123
2026-06-11 07:14:39 +00:00
committed by GitHub
co-authored by autofix-ci[bot]
parent c4a8d79be9
commit fb39df49c8
18 changed files with 406 additions and 91 deletions
@@ -508,7 +508,32 @@ def _shell_cli_tool(item: object) -> DifyShellCliToolConfig | None:
name = data.get("name") or data.get("tool_name") or data.get("label")
if not commands and not isinstance(name, str):
return None
return DifyShellCliToolConfig(name=name if isinstance(name, str) else None, install_commands=commands)
tool_env = data.get("env") if isinstance(data.get("env"), Mapping) else {}
env = [
env_var
for env_var in (_shell_env_var(item) for item in _env_entries(tool_env, "variables"))
if env_var is not None
]
secret_refs = [
secret_ref
for secret_ref in (_shell_secret_ref(item) for item in _env_entries(tool_env, "secret_refs"))
if secret_ref is not None
]
return DifyShellCliToolConfig(
name=name if isinstance(name, str) else None,
install_commands=commands,
env=env,
secret_refs=secret_refs,
)
def _env_entries(env: object, key: str) -> list[object]:
if not isinstance(env, Mapping):
return []
entries = env.get(key)
if not isinstance(entries, list):
return []
return entries
def _shell_env_var(item: object) -> DifyShellEnvVarConfig | None:
+43 -5
View File
@@ -363,8 +363,37 @@ class WorkflowAgentNodeValidator:
agent_soul: AgentSoulConfig,
) -> None:
seen_names: set[str] = set()
for env_var in agent_soul.env.variables:
name = env_var.name
cls._validate_env_entries(
binding=binding,
seen_names=seen_names,
variables=agent_soul.env.variables,
secret_refs=agent_soul.env.secret_refs,
label="agent",
)
for cli_tool in agent_soul.tools.cli_tools:
if not cli_tool.enabled:
continue
name = cli_tool.get("name") or cli_tool.get("tool_name") or cli_tool.get("label") or "<unnamed>"
cls._validate_env_entries(
binding=binding,
seen_names=seen_names,
variables=cli_tool.env.variables,
secret_refs=cli_tool.env.secret_refs,
label=f"CLI Tool {name}",
)
@classmethod
def _validate_env_entries(
cls,
*,
binding: WorkflowAgentNodeBinding,
seen_names: set[str],
variables: list[Any],
secret_refs: list[Any],
label: str,
) -> None:
for env_var in variables:
name = cls._env_name(env_var)
if not name:
continue
if name in seen_names:
@@ -372,13 +401,13 @@ class WorkflowAgentNodeValidator:
f"Workflow Agent node {binding.node_id} has duplicate env/secret name {name}."
)
seen_names.add(name)
for secret_ref in agent_soul.env.secret_refs:
name = secret_ref.name
for secret_ref in secret_refs:
name = cls._env_name(secret_ref)
if not name:
continue
if cls._permission_denied(secret_ref.model_dump(mode="python", exclude_none=True, exclude_defaults=True)):
raise WorkflowAgentNodeValidationError(
f"Workflow Agent node {binding.node_id} has unauthorized secret reference {name}."
f"Workflow Agent node {binding.node_id} has unauthorized secret reference {name} in {label}."
)
if name in seen_names:
raise WorkflowAgentNodeValidationError(
@@ -386,6 +415,15 @@ class WorkflowAgentNodeValidator:
)
seen_names.add(name)
@staticmethod
def _env_name(value: Any) -> str | None:
if hasattr(value, "get"):
for key in ("name", "key", "env_name", "variable"):
item = value.get(key)
if isinstance(item, str) and item.strip():
return item.strip()
return None
@classmethod
def _validate_tool_node_agentic_mode(cls, *, node_id: str, node_data: Mapping[str, Any]) -> None:
agentic_config = cls._extract_tool_agentic_config(node_data)