From 511dbb9974fb347cecb2673140ade0fa0b04f21a Mon Sep 17 00:00:00 2001 From: Yunlu Wen Date: Thu, 16 Jul 2026 11:31:16 +0800 Subject: [PATCH] fix(agent): add new envs to .env.example (#39041) --- dify-agent-runtime/Makefile | 2 +- dify-agent-runtime/README.md | 12 ++++++------ dify-agent-runtime/internal/envvar/envvar.go | 8 ++++---- dify-agent-runtime/internal/landlock/config.go | 4 ---- dify-agent-runtime/tests/acceptance_test.go | 10 +++++----- docker/.env.example | 9 +++++++++ docker/docker-compose-template.yaml | 9 ++++++++- docker/docker-compose.yaml | 9 ++++++++- docker/envs/core-services/dify-agent.env.example | 14 ++++++++++++++ 9 files changed, 55 insertions(+), 22 deletions(-) diff --git a/dify-agent-runtime/Makefile b/dify-agent-runtime/Makefile index 40cf168c18a..fffa071cc3b 100644 --- a/dify-agent-runtime/Makefile +++ b/dify-agent-runtime/Makefile @@ -94,7 +94,7 @@ integration-up: docker run -d --name $(CONTAINER_NAME_NOISO) \ -p $(HOST_PORT_NOISO):5004 \ -e SHELLCTL_AUTH_TOKEN=$(AUTH_TOKEN_NOISO) \ - -e ENABLE_PATH_ISOLATION=false \ + -e SHELLCTL_ENABLE_PATH_ISOLATION=false \ $(IMAGE_NAME) @echo 'CONTAINER_NAME_NOISO=$(CONTAINER_NAME_NOISO)' >> $(STATE_FILE) @echo 'HOST_PORT_NOISO=$(HOST_PORT_NOISO)' >> $(STATE_FILE) diff --git a/dify-agent-runtime/README.md b/dify-agent-runtime/README.md index 7abc105211f..9e08532a5b5 100644 --- a/dify-agent-runtime/README.md +++ b/dify-agent-runtime/README.md @@ -78,12 +78,12 @@ The runner automatically creates `$CWD/.tmp` and sets `TMPDIR`, `TMP`, `TEMP` to ### Environment Variables -| Variable | Default | Description | -| ----------------------- | --------------- | ------------------------------------------------ | -| `ENABLE_PATH_ISOLATION` | `true` | Set to `false` to disable Landlock entirely | -| `LANDLOCK_RW_PATHS` | _(empty)_ | Comma-separated RW directories (besides `$HOME`) | -| `LANDLOCK_RO_PATHS` | `/usr,/bin,...` | Comma-separated RO+exec directories | -| `LANDLOCK_RW_DEV_PATHS` | `/dev/null,...` | Comma-separated device files with RW access | +| Variable | Default | Description | +|----------|---------|-------------| +| `SHELLCTL_ENABLE_PATH_ISOLATION` | `true` | Set to `false` to disable Landlock entirely | +| `SHELLCTL_LANDLOCK_RW_PATHS` | *(empty)* | Comma-separated RW directories (besides `$HOME`) | +| `SHELLCTL_LANDLOCK_RO_PATHS` | `/usr,/bin,...` | Comma-separated RO+exec directories | +| `SHELLCTL_LANDLOCK_RW_DEV_PATHS` | `/dev/null,...` | Comma-separated device files with RW access | Requires Linux ≥ 5.13. On unsupported kernels, a warning is printed to stderr. diff --git a/dify-agent-runtime/internal/envvar/envvar.go b/dify-agent-runtime/internal/envvar/envvar.go index 7ecbd96b503..e93af4e828c 100644 --- a/dify-agent-runtime/internal/envvar/envvar.go +++ b/dify-agent-runtime/internal/envvar/envvar.go @@ -8,16 +8,16 @@ import "os" const ( // EnvEnablePathIsolation controls whether Landlock is applied at all. - EnvEnablePathIsolation = "ENABLE_PATH_ISOLATION" + EnvEnablePathIsolation = "SHELLCTL_ENABLE_PATH_ISOLATION" // EnvRWPaths overrides the default RW directories (comma-separated). - EnvRWPaths = "LANDLOCK_RW_PATHS" + EnvRWPaths = "SHELLCTL_LANDLOCK_RW_PATHS" // EnvROPaths overrides the default RO+exec directories (comma-separated). - EnvROPaths = "LANDLOCK_RO_PATHS" + EnvROPaths = "SHELLCTL_LANDLOCK_RO_PATHS" // EnvRWDevPaths overrides the default device files (comma-separated). - EnvRWDevPaths = "LANDLOCK_RW_DEV_PATHS" + EnvRWDevPaths = "SHELLCTL_LANDLOCK_RW_DEV_PATHS" ) // --- Agent Stub --- diff --git a/dify-agent-runtime/internal/landlock/config.go b/dify-agent-runtime/internal/landlock/config.go index 73cd791caa5..46e10e55474 100644 --- a/dify-agent-runtime/internal/landlock/config.go +++ b/dify-agent-runtime/internal/landlock/config.go @@ -63,10 +63,6 @@ func DefaultConfig(home, cwd, jobDir string) *Config { // // If a variable is set (even to empty string), its value replaces the default. // Set to empty to grant no additional paths beyond $HOME. -// -// LANDLOCK_RW_PATHS — comma-separated RW dirs (default: empty) -// LANDLOCK_RO_PATHS — comma-separated RO dirs (default: system paths) -// LANDLOCK_RW_DEV_PATHS — comma-separated dev files (default: /dev/null,...) func ConfigFromEnv(home, cwd, jobDir string) *Config { cfg := DefaultConfig(home, cwd, jobDir) diff --git a/dify-agent-runtime/tests/acceptance_test.go b/dify-agent-runtime/tests/acceptance_test.go index caf3b773791..aed05e6ac9d 100644 --- a/dify-agent-runtime/tests/acceptance_test.go +++ b/dify-agent-runtime/tests/acceptance_test.go @@ -622,7 +622,7 @@ func TestLandlockCannotReadOtherAgentHome(t *testing.T) { // --- Landlock Disable / Bypass Tests --- // TestLandlockDisabledAllowsWriteOutsideHome uses the pre-started no-isolation -// container (ENABLE_PATH_ISOLATION=false) and verifies that isolation is off. +// container (SHELLCTL_ENABLE_PATH_ISOLATION=false) and verifies that isolation is off. func TestLandlockDisabledAllowsWriteOutsideHome(t *testing.T) { tgt, ok := noIsolationTarget() if !ok { @@ -645,7 +645,7 @@ func TestLandlockDisabledAllowsWriteOutsideHome(t *testing.T) { } // TestLandlockEnvBypassBlocked verifies that a caller cannot set -// ENABLE_PATH_ISOLATION=false in job env to escape the sandbox. +// SHELLCTL_ENABLE_PATH_ISOLATION=false in job env to escape the sandbox. func TestLandlockEnvBypassBlocked(t *testing.T) { for _, tgt := range targets() { t.Run(tgt.name, func(t *testing.T) { @@ -653,8 +653,8 @@ func TestLandlockEnvBypassBlocked(t *testing.T) { result := runJob(t, tgt, map[string]any{ "script": "touch /opt/landlock-bypass-test 2>&1; echo exit=$?", "env": map[string]string{ - "HOME": "/home/dify", - "ENABLE_PATH_ISOLATION": "false", + "HOME": "/home/dify", + "SHELLCTL_ENABLE_PATH_ISOLATION": "false", }, "timeout": 10, }) @@ -662,7 +662,7 @@ func TestLandlockEnvBypassBlocked(t *testing.T) { output := result["output"].(string) // The write should still be denied despite the env override attempt. if strings.Contains(output, "exit=0") { - t.Errorf("expected write to /opt to be DENIED even with ENABLE_PATH_ISOLATION=false in job env, but it succeeded: %q", output) + t.Errorf("expected write to /opt to be DENIED even with SHELLCTL_ENABLE_PATH_ISOLATION=false in job env, but it succeeded: %q", output) } }) } diff --git a/docker/.env.example b/docker/.env.example index dfddb102949..d46247f696f 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -270,6 +270,15 @@ DIFY_AGENT_STUB_API_BASE_URL=http://agent_backend:5050/agent-stub # Replace this development default in production. # Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))' DIFY_AGENT_SERVER_SECRET_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY +# Agent sandbox path isolation (Landlock), applied inside the local_sandbox container. +# Set SHELLCTL_ENABLE_PATH_ISOLATION=false to disable Landlock entirely (default: true). +SHELLCTL_ENABLE_PATH_ISOLATION=true +# The paths below override the built-in defaults when set (even to an empty value). +# Leave them commented out to keep the defaults; setting SHELLCTL_LANDLOCK_RO_PATHS or +# SHELLCTL_LANDLOCK_RW_DEV_PATHS to an empty string removes all default paths and can break exec. +# SHELLCTL_LANDLOCK_RW_PATHS= +# SHELLCTL_LANDLOCK_RO_PATHS= +# SHELLCTL_LANDLOCK_RW_DEV_PATHS= # Nginx and Docker Compose NGINX_SERVER_NAME=_ diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index e320f9c1c98..8404764f58d 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -527,7 +527,14 @@ services: image: langgenius/dify-agent-local-sandbox:1.16.0-rc1 restart: always environment: - SHELLCTL_AUTH_TOKEN: ${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-} + - SHELLCTL_AUTH_TOKEN=${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-} + # Landlock path isolation. SHELLCTL_ENABLE_PATH_ISOLATION defaults to true in the runtime. + - SHELLCTL_ENABLE_PATH_ISOLATION=${SHELLCTL_ENABLE_PATH_ISOLATION:-true} + # Passed through only when set (uncommented) in .env; leaving them unset keeps + # the runtime's built-in defaults. Setting them to empty removes all default paths. + - SHELLCTL_LANDLOCK_RW_PATHS + - SHELLCTL_LANDLOCK_RO_PATHS + - SHELLCTL_LANDLOCK_RW_DEV_PATHS healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5004/healthz"] interval: 30s diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 0bbd77a9e94..69ea2c81103 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -533,7 +533,14 @@ services: image: langgenius/dify-agent-local-sandbox:1.16.0-rc1 restart: always environment: - SHELLCTL_AUTH_TOKEN: ${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-} + - SHELLCTL_AUTH_TOKEN=${DIFY_AGENT_SHELLCTL_AUTH_TOKEN:-} + # Landlock path isolation. SHELLCTL_ENABLE_PATH_ISOLATION defaults to true in the runtime. + - SHELLCTL_ENABLE_PATH_ISOLATION=${SHELLCTL_ENABLE_PATH_ISOLATION:-true} + # Passed through only when set (uncommented) in .env; leaving them unset keeps + # the runtime's built-in defaults. Setting them to empty removes all default paths. + - SHELLCTL_LANDLOCK_RW_PATHS + - SHELLCTL_LANDLOCK_RO_PATHS + - SHELLCTL_LANDLOCK_RW_DEV_PATHS healthcheck: test: ["CMD", "curl", "-f", "http://localhost:5004/healthz"] interval: 30s diff --git a/docker/envs/core-services/dify-agent.env.example b/docker/envs/core-services/dify-agent.env.example index be757e456bb..7eeee49fdbe 100644 --- a/docker/envs/core-services/dify-agent.env.example +++ b/docker/envs/core-services/dify-agent.env.example @@ -26,3 +26,17 @@ DIFY_AGENT_STUB_API_BASE_URL=http://agent_backend:5050/agent-stub # Replace this development default in production. # Generate one with: python -c 'import secrets; print(secrets.token_urlsafe(32))' DIFY_AGENT_SERVER_SECRET_KEY=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY + +# --- Agent sandbox path isolation (Landlock) --- +# Applied by the runtime inside the local_sandbox container. +# Set SHELLCTL_ENABLE_PATH_ISOLATION=false to disable Landlock entirely (default: true). +SHELLCTL_ENABLE_PATH_ISOLATION=true +# The paths below override the built-in defaults when set (even to an empty value). +# Leave them commented out to keep the defaults; setting SHELLCTL_LANDLOCK_RO_PATHS or +# SHELLCTL_LANDLOCK_RW_DEV_PATHS to an empty string removes all default paths and can break exec. +# Comma-separated additional read-write directories (default: none beyond $HOME). +# SHELLCTL_LANDLOCK_RW_PATHS= +# Comma-separated read-only + execute directories (default: /usr,/bin,/sbin,/lib,/lib64,/etc,/proc,/opt/dify-agent-tools,/opt/homebrew,/snap). +# SHELLCTL_LANDLOCK_RO_PATHS= +# Comma-separated read-write device files (default: /dev/null,/dev/zero,/dev/urandom,/dev/random,/dev/tty). +# SHELLCTL_LANDLOCK_RW_DEV_PATHS=