mirror of
https://github.com/langgenius/dify.git
synced 2026-07-30 16:59:35 +08:00
fix: fix hardcode /home/dify (#39767)
This commit is contained in:
parent
0441d27cac
commit
080a1d42f2
@ -80,6 +80,10 @@ Binding backend. A standalone Local server normally uses:
|
||||
DIFY_AGENT_RUNTIME_BACKEND=local
|
||||
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT=http://127.0.0.1:5004
|
||||
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=
|
||||
# Optional when shellctl runs directly on a host without /home/dify:
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT=/tmp/dify-agent/materialized-homes
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_WORKSPACE_ROOT=/tmp/dify-agent/workspaces
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_HOME_SNAPSHOT_ROOT=/tmp/dify-agent/home-snapshots
|
||||
DIFY_AGENT_SANDBOX_FILE_UPLOAD_MAX_BYTES=52428800
|
||||
```
|
||||
|
||||
|
||||
@ -42,6 +42,9 @@ also reads `.env` and `dify-agent/.env` when present.
|
||||
| `DIFY_AGENT_RUNTIME_BACKEND` | `local` | Selects one coherent `local`, `enterprise`, or `e2b` Home Snapshot + Execution Binding backend profile. |
|
||||
| `DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT` | empty | Local shellctl data-plane URL. With the default Local selection, leaving it empty disables `dify.runtime` and resource endpoints. |
|
||||
| `DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN` | empty | Optional bearer token sent to Local shellctl. |
|
||||
| `DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT` | `/home/dify/.dify-agent-materialized-homes` | Root directory, on the Local shellctl filesystem, for per-Binding materialized Homes. |
|
||||
| `DIFY_AGENT_LOCAL_SANDBOX_WORKSPACE_ROOT` | `/home/dify/.dify-agent-workspaces` | Root directory, on the Local shellctl filesystem, for mutable Workspaces. |
|
||||
| `DIFY_AGENT_LOCAL_SANDBOX_HOME_SNAPSHOT_ROOT` | `/home/dify/.dify-agent-home-snapshots` | Root directory, on the Local shellctl filesystem, for immutable Home Snapshots. |
|
||||
| `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_ENDPOINT` | empty | Enterprise Gateway endpoint required by configuration. Default-Home Bindings are supported; immutable Home Snapshot operations remain unsupported. |
|
||||
| `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_AUTH_TOKEN` | empty | Optional `X-Inner-Api-Key` sent to the Enterprise Gateway. |
|
||||
| `DIFY_AGENT_ENTERPRISE_SANDBOX_GATEWAY_TIMEOUT` | `30` | Enterprise control-plane timeout in seconds. |
|
||||
@ -78,6 +81,10 @@ DIFY_AGENT_INNER_API_KEY=replace-with-dify-inner-api-key-for-plugin
|
||||
DIFY_AGENT_RUNTIME_BACKEND=local
|
||||
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT=http://127.0.0.1:5004
|
||||
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=replace-with-shellctl-token
|
||||
# Set these when shellctl runs directly on a host that does not have /home/dify.
|
||||
DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT=/tmp/dify-agent/materialized-homes
|
||||
DIFY_AGENT_LOCAL_SANDBOX_WORKSPACE_ROOT=/tmp/dify-agent/workspaces
|
||||
DIFY_AGENT_LOCAL_SANDBOX_HOME_SNAPSHOT_ROOT=/tmp/dify-agent/home-snapshots
|
||||
DIFY_AGENT_SANDBOX_FILE_UPLOAD_MAX_BYTES=52428800
|
||||
DIFY_AGENT_STUB_API_BASE_URL=https://agent.example.com/agent-stub
|
||||
# This is security-sensitive: it derives the JWE encryption key for Agent Stub bearer tokens.
|
||||
@ -90,7 +97,7 @@ DIFY_AGENT_SERVER_SECRET_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY
|
||||
accepted only as legacy aliases for the two Local settings. New deployments
|
||||
must use `DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT` and
|
||||
`DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN`. There is no compatibility setting for
|
||||
the removed shell-provider selector or Shell-owned Home root.
|
||||
the removed shell-provider selector.
|
||||
|
||||
The example above is for a standalone Dify Agent process, where the byte limit
|
||||
can be set directly. In a Docker deployment, set `PLUGIN_MAX_FILE_SIZE` in
|
||||
|
||||
@ -71,6 +71,10 @@ Equivalent standalone environment settings are:
|
||||
DIFY_AGENT_RUNTIME_BACKEND=local
|
||||
DIFY_AGENT_LOCAL_SANDBOX_ENDPOINT=http://127.0.0.1:5004
|
||||
DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN=replace-with-shellctl-token
|
||||
# Optional when shellctl runs directly on a host without /home/dify:
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_MATERIALIZED_HOME_ROOT=/tmp/dify-agent/materialized-homes
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_WORKSPACE_ROOT=/tmp/dify-agent/workspaces
|
||||
# DIFY_AGENT_LOCAL_SANDBOX_HOME_SNAPSHOT_ROOT=/tmp/dify-agent/home-snapshots
|
||||
```
|
||||
|
||||
The auth token may be empty when shellctl authentication is disabled. E2B uses
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import posixpath
|
||||
from typing import ClassVar, Literal, Self
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@ -19,6 +20,9 @@ from dify_agent.runtime_backend.local import LocalExecutionBindingBackend, Local
|
||||
from dify_agent.runtime_backend.protocols import RuntimeBackendProfile
|
||||
|
||||
DEFAULT_E2B_TEMPLATE = "difys-default-team/dify-agent-local-sandbox"
|
||||
DEFAULT_LOCAL_MATERIALIZED_HOME_ROOT = "/home/dify/.dify-agent-materialized-homes"
|
||||
DEFAULT_LOCAL_WORKSPACE_ROOT = "/home/dify/.dify-agent-workspaces"
|
||||
DEFAULT_LOCAL_HOME_SNAPSHOT_ROOT = "/home/dify/.dify-agent-home-snapshots"
|
||||
|
||||
|
||||
class RuntimeBackendSettings(BaseSettings):
|
||||
@ -40,6 +44,9 @@ class RuntimeBackendSettings(BaseSettings):
|
||||
"DIFY_AGENT_SHELLCTL_AUTH_TOKEN",
|
||||
),
|
||||
)
|
||||
local_sandbox_materialized_home_root: str = DEFAULT_LOCAL_MATERIALIZED_HOME_ROOT
|
||||
local_sandbox_workspace_root: str = DEFAULT_LOCAL_WORKSPACE_ROOT
|
||||
local_sandbox_home_snapshot_root: str = DEFAULT_LOCAL_HOME_SNAPSHOT_ROOT
|
||||
|
||||
enterprise_sandbox_gateway_endpoint: str | None = None
|
||||
enterprise_sandbox_gateway_auth_token: str | None = None
|
||||
@ -70,6 +77,18 @@ class RuntimeBackendSettings(BaseSettings):
|
||||
if not self.local_sandbox_endpoint or not self.local_sandbox_endpoint.strip():
|
||||
raise ValueError("local_sandbox_endpoint is required for the local runtime backend")
|
||||
_validate_http_url(self.local_sandbox_endpoint, field_name="local_sandbox_endpoint")
|
||||
_validate_absolute_posix_path(
|
||||
self.local_sandbox_materialized_home_root,
|
||||
field_name="local_sandbox_materialized_home_root",
|
||||
)
|
||||
_validate_absolute_posix_path(
|
||||
self.local_sandbox_workspace_root,
|
||||
field_name="local_sandbox_workspace_root",
|
||||
)
|
||||
_validate_absolute_posix_path(
|
||||
self.local_sandbox_home_snapshot_root,
|
||||
field_name="local_sandbox_home_snapshot_root",
|
||||
)
|
||||
case "enterprise":
|
||||
endpoint = self.enterprise_sandbox_gateway_endpoint
|
||||
if not endpoint or not endpoint.strip():
|
||||
@ -92,8 +111,18 @@ def create_runtime_backend_profile(settings: RuntimeBackendSettings) -> RuntimeB
|
||||
endpoint = settings.local_sandbox_endpoint or ""
|
||||
token = settings.local_sandbox_auth_token or ""
|
||||
return RuntimeBackendProfile(
|
||||
home_snapshots=LocalHomeSnapshotBackend(endpoint=endpoint, auth_token=token),
|
||||
execution_bindings=LocalExecutionBindingBackend(endpoint=endpoint, auth_token=token),
|
||||
home_snapshots=LocalHomeSnapshotBackend(
|
||||
endpoint=endpoint,
|
||||
auth_token=token,
|
||||
snapshot_root=settings.local_sandbox_home_snapshot_root,
|
||||
),
|
||||
execution_bindings=LocalExecutionBindingBackend(
|
||||
endpoint=endpoint,
|
||||
auth_token=token,
|
||||
materialized_home_root=settings.local_sandbox_materialized_home_root,
|
||||
workspace_root=settings.local_sandbox_workspace_root,
|
||||
snapshot_root=settings.local_sandbox_home_snapshot_root,
|
||||
),
|
||||
)
|
||||
case "enterprise":
|
||||
endpoint = settings.enterprise_sandbox_gateway_endpoint or ""
|
||||
@ -129,4 +158,16 @@ def _validate_http_url(value: str, *, field_name: str) -> None:
|
||||
raise ValueError(f"{field_name} must be a valid http(s) URL")
|
||||
|
||||
|
||||
__all__ = ["DEFAULT_E2B_TEMPLATE", "RuntimeBackendSettings", "create_runtime_backend_profile"]
|
||||
def _validate_absolute_posix_path(value: str, *, field_name: str) -> None:
|
||||
if not value.strip() or not posixpath.isabs(value):
|
||||
raise ValueError(f"{field_name} must be an absolute POSIX path")
|
||||
|
||||
|
||||
__all__ = [
|
||||
"DEFAULT_E2B_TEMPLATE",
|
||||
"DEFAULT_LOCAL_HOME_SNAPSHOT_ROOT",
|
||||
"DEFAULT_LOCAL_MATERIALIZED_HOME_ROOT",
|
||||
"DEFAULT_LOCAL_WORKSPACE_ROOT",
|
||||
"RuntimeBackendSettings",
|
||||
"create_runtime_backend_profile",
|
||||
]
|
||||
|
||||
@ -25,7 +25,13 @@ from dify_agent.agent_stub.server.grpc_bind import normalize_agent_stub_grpc_bin
|
||||
from dify_agent.agent_stub.server.tokens.agent_stub import AgentStubTokenCodec, decode_server_secret_key
|
||||
from dify_agent.runtime_backend import RuntimeBackendProfile
|
||||
from dify_agent.runtime_backend.e2b import E2B_MAX_ACTIVE_TIMEOUT_SECONDS
|
||||
from dify_agent.runtime_backend.profile import RuntimeBackendSettings, create_runtime_backend_profile
|
||||
from dify_agent.runtime_backend.profile import (
|
||||
DEFAULT_LOCAL_HOME_SNAPSHOT_ROOT,
|
||||
DEFAULT_LOCAL_MATERIALIZED_HOME_ROOT,
|
||||
DEFAULT_LOCAL_WORKSPACE_ROOT,
|
||||
RuntimeBackendSettings,
|
||||
create_runtime_backend_profile,
|
||||
)
|
||||
|
||||
DEFAULT_RUN_RETENTION_SECONDS = 3 * 24 * 60 * 60
|
||||
|
||||
@ -50,6 +56,9 @@ class ServerSettings(BaseSettings):
|
||||
default=None,
|
||||
validation_alias=AliasChoices("DIFY_AGENT_LOCAL_SANDBOX_AUTH_TOKEN", "DIFY_AGENT_SHELLCTL_AUTH_TOKEN"),
|
||||
)
|
||||
local_sandbox_materialized_home_root: str = DEFAULT_LOCAL_MATERIALIZED_HOME_ROOT
|
||||
local_sandbox_workspace_root: str = DEFAULT_LOCAL_WORKSPACE_ROOT
|
||||
local_sandbox_home_snapshot_root: str = DEFAULT_LOCAL_HOME_SNAPSHOT_ROOT
|
||||
enterprise_sandbox_gateway_endpoint: str | None = None
|
||||
enterprise_sandbox_gateway_auth_token: str | None = None
|
||||
enterprise_sandbox_gateway_timeout: float = Field(default=30.0, gt=0)
|
||||
@ -178,6 +187,9 @@ class ServerSettings(BaseSettings):
|
||||
runtime_backend=self.runtime_backend,
|
||||
local_sandbox_endpoint=self.local_sandbox_endpoint,
|
||||
local_sandbox_auth_token=self.local_sandbox_auth_token,
|
||||
local_sandbox_materialized_home_root=self.local_sandbox_materialized_home_root,
|
||||
local_sandbox_workspace_root=self.local_sandbox_workspace_root,
|
||||
local_sandbox_home_snapshot_root=self.local_sandbox_home_snapshot_root,
|
||||
enterprise_sandbox_gateway_endpoint=self.enterprise_sandbox_gateway_endpoint,
|
||||
enterprise_sandbox_gateway_auth_token=self.enterprise_sandbox_gateway_auth_token,
|
||||
enterprise_sandbox_gateway_timeout=self.enterprise_sandbox_gateway_timeout,
|
||||
|
||||
@ -4,7 +4,12 @@ import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from dify_agent.runtime_backend.e2b import E2B_MAX_ACTIVE_TIMEOUT_SECONDS
|
||||
from dify_agent.runtime_backend.profile import DEFAULT_E2B_TEMPLATE, RuntimeBackendSettings
|
||||
from dify_agent.runtime_backend.local import LocalExecutionBindingBackend, LocalHomeSnapshotBackend
|
||||
from dify_agent.runtime_backend.profile import (
|
||||
DEFAULT_E2B_TEMPLATE,
|
||||
RuntimeBackendSettings,
|
||||
create_runtime_backend_profile,
|
||||
)
|
||||
|
||||
|
||||
def test_e2b_backend_uses_prepared_dify_template_by_default() -> None:
|
||||
@ -32,3 +37,31 @@ def test_e2b_backend_rejects_active_timeout_above_platform_limit() -> None:
|
||||
def test_local_backend_requires_shellctl_endpoint() -> None:
|
||||
with pytest.raises(ValidationError, match="local_sandbox_endpoint"):
|
||||
_ = RuntimeBackendSettings(runtime_backend="local")
|
||||
|
||||
|
||||
def test_local_backend_passes_configured_roots_to_drivers() -> None:
|
||||
settings = RuntimeBackendSettings(
|
||||
runtime_backend="local",
|
||||
local_sandbox_endpoint="http://shellctl.example",
|
||||
local_sandbox_materialized_home_root="/tmp/dify/homes",
|
||||
local_sandbox_workspace_root="/tmp/dify/workspaces",
|
||||
local_sandbox_home_snapshot_root="/tmp/dify/snapshots",
|
||||
)
|
||||
|
||||
profile = create_runtime_backend_profile(settings)
|
||||
|
||||
assert isinstance(profile.execution_bindings, LocalExecutionBindingBackend)
|
||||
assert isinstance(profile.home_snapshots, LocalHomeSnapshotBackend)
|
||||
assert profile.execution_bindings.materialized_home_root == "/tmp/dify/homes"
|
||||
assert profile.execution_bindings.workspace_root == "/tmp/dify/workspaces"
|
||||
assert profile.execution_bindings.snapshot_root == "/tmp/dify/snapshots"
|
||||
assert profile.home_snapshots.snapshot_root == "/tmp/dify/snapshots"
|
||||
|
||||
|
||||
def test_local_backend_rejects_relative_roots() -> None:
|
||||
with pytest.raises(ValidationError, match="absolute POSIX path"):
|
||||
_ = RuntimeBackendSettings(
|
||||
runtime_backend="local",
|
||||
local_sandbox_endpoint="http://shellctl.example",
|
||||
local_sandbox_workspace_root="relative/workspaces",
|
||||
)
|
||||
|
||||
@ -14,7 +14,7 @@ from dify_agent.agent_stub.server.tokens.agent_stub import AgentStubTokenCodec
|
||||
from dify_agent.server.settings import ServerSettings
|
||||
from dify_agent.runtime_backend.e2b import E2BExecutionBindingBackend
|
||||
from dify_agent.runtime_backend.enterprise import EnterpriseExecutionBindingBackend
|
||||
from dify_agent.runtime_backend.local import LocalExecutionBindingBackend
|
||||
from dify_agent.runtime_backend.local import LocalExecutionBindingBackend, LocalHomeSnapshotBackend
|
||||
|
||||
|
||||
def _base64url_secret(value: bytes) -> str:
|
||||
@ -260,14 +260,22 @@ def test_build_runtime_backend_profile_returns_local_drivers_when_configured() -
|
||||
runtime_backend="local",
|
||||
local_sandbox_endpoint="http://shellctl.example",
|
||||
local_sandbox_auth_token="shell-secret",
|
||||
local_sandbox_materialized_home_root="/tmp/dify/homes",
|
||||
local_sandbox_workspace_root="/tmp/dify/workspaces",
|
||||
local_sandbox_home_snapshot_root="/tmp/dify/snapshots",
|
||||
)
|
||||
|
||||
profile = settings.build_runtime_backend_profile()
|
||||
|
||||
assert profile is not None
|
||||
assert isinstance(profile.execution_bindings, LocalExecutionBindingBackend)
|
||||
assert isinstance(profile.home_snapshots, LocalHomeSnapshotBackend)
|
||||
assert profile.execution_bindings.endpoint == "http://shellctl.example"
|
||||
assert profile.execution_bindings.auth_token == "shell-secret"
|
||||
assert profile.execution_bindings.materialized_home_root == "/tmp/dify/homes"
|
||||
assert profile.execution_bindings.workspace_root == "/tmp/dify/workspaces"
|
||||
assert profile.execution_bindings.snapshot_root == "/tmp/dify/snapshots"
|
||||
assert profile.home_snapshots.snapshot_root == "/tmp/dify/snapshots"
|
||||
|
||||
|
||||
def test_build_runtime_backend_profile_returns_enterprise_drivers_when_selected() -> None:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user