From 63e4b92a521e0f5e2e4b3503df329373727cdf89 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 20 Sep 2026 16:25:34 -0400 Subject: [PATCH] fix: forward every environment-overridable dokku variable `DOKKU_INIT_SYSTEM` reaches the `dokku` user only through the environment while the Docker image is being built, so narrowing the forwarded set left `nginx:reload` taking the systemd branch during `debian/postinst` and blocking on a sudo password prompt until the build timed out. The forwarded set now covers every variable `dokku` honours from the environment, and `DOKKU_PRESERVE_ENV` still carries anything beyond it. --- docs/configuration/environment-variables.md | 5 +++++ plugins/common/functions | 13 +++++++++--- tests/unit/core_1.bats | 23 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/docs/configuration/environment-variables.md b/docs/configuration/environment-variables.md index 203e8a5e2..968c63308 100644 --- a/docs/configuration/environment-variables.md +++ b/docs/configuration/environment-variables.md @@ -165,6 +165,11 @@ named explicitly and forwarded: | `DOKKU_DISABLE_TTY`, `DOKKU_FORCE_TTY` | the `dokku run` tty flags, or the environment | | `DOKKU_PRESERVE_ENV` | the list below | | `SSH_USER`, `SSH_NAME`, `NAME`, `FINGERPRINT`, `SSH_ORIGINAL_COMMAND` | the ssh session the command arrived on | +| `DOCKER_BIN`, `DOKKU_CNB_BUILDER`, `DOKKU_EVENTS_LOGFILE`, `DOKKU_HOST_ROOT`, `DOKKU_IMAGE`, `DOKKU_LIB_PATH`, `DOKKU_LOGS_DIR`, `DOKKU_LOGS_HOST_DIR`, `DOKKU_ROOT`, `DOKKU_SYSTEM_GROUP`, `DOKKU_SYSTEM_USER`, `PLUGIN_PATH`, `PLUGIN_AVAILABLE_PATH`, `PLUGIN_ENABLED_PATH`, `PLUGIN_CORE_PATH`, `PLUGIN_CORE_AVAILABLE_PATH`, `PLUGIN_CORE_ENABLED_PATH` | the environment, so the re-executed process derives the same paths as the caller | +| `DOKKU_INIT_SYSTEM`, `DOKKU_LIB_HOST_ROOT` | the environment, which is where they live while a Docker image is being built | + +`DOKKU_PID` is deliberately not forwarded: it is unset before the privilege drop so the re-executed +process gets its own. To forward anything else - a variable read by a third-party plugin, or a one-off override of a setting that normally lives in `/etc/default/dokku` - name it in `DOKKU_PRESERVE_ENV`: diff --git a/plugins/common/functions b/plugins/common/functions index 9d9ce9128..2b13b9416 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -479,11 +479,18 @@ is_abs_path() { fn-cli-preserved-env-names() { declare desc="names the environment variables the re-exec as the dokku user must carry" - # anything sourced from /etc/default/dokku or ~dokku/.dokkurc/* is re-read by the - # child and does not belong here; DOKKU_PRESERVE_ENV carries anything else + # every variable dokku honours from the environment has to be listed, or the child + # derives different values than the parent - during the docker image build these only + # ever exist in the environment. DOKKU_PID is the one exclusion: it is unset above so + # the child gets its own. DOKKU_PRESERVE_ENV carries anything else echo "DOKKU_APP_NAME DOKKU_APPS_FORCE_DELETE DOKKU_DISABLE_TTY DOKKU_FORCE_TTY" \ "DOKKU_GLOBAL_FLAGS DOKKU_PRESERVE_ENV DOKKU_QUIET_OUTPUT DOKKU_TRACE" \ - "FINGERPRINT NAME SSH_NAME SSH_ORIGINAL_COMMAND SSH_USER" + "FINGERPRINT NAME SSH_NAME SSH_ORIGINAL_COMMAND SSH_USER" \ + "DOCKER_BIN DOKKU_CNB_BUILDER DOKKU_EVENTS_LOGFILE DOKKU_HOST_ROOT DOKKU_IMAGE" \ + "DOKKU_INIT_SYSTEM DOKKU_LIB_HOST_ROOT DOKKU_LIB_PATH DOKKU_LOGS_DIR" \ + "DOKKU_LOGS_HOST_DIR DOKKU_ROOT DOKKU_SYSTEM_GROUP DOKKU_SYSTEM_USER" \ + "PLUGIN_AVAILABLE_PATH PLUGIN_CORE_AVAILABLE_PATH PLUGIN_CORE_ENABLED_PATH" \ + "PLUGIN_CORE_PATH PLUGIN_ENABLED_PATH PLUGIN_PATH" } fn-sudo-preserve-env-flag() { diff --git a/tests/unit/core_1.bats b/tests/unit/core_1.bats index 5e1217fb8..11cacfdca 100644 --- a/tests/unit/core_1.bats +++ b/tests/unit/core_1.bats @@ -164,6 +164,29 @@ teardown() { assert_output "7" } +@test "(common) [preserve-env] fn-cli-preserved-env-names covers the docker image build variables" { + # neither is read by the dokku script itself, so the derivation test below does not + # catch them. both exist only in the environment while the docker image is built + run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-cli-preserved-env-names | tr ' ' '\\n' | grep -cxE 'DOKKU_INIT_SYSTEM|DOKKU_LIB_HOST_ROOT'" + echo "output: $output" + echo "status: $status" + assert_success + assert_output "2" +} + +@test "(common) [preserve-env] every environment-overridable dokku variable is preserved" { + # test_helper leaves these unexported, so the single-quoted script below cannot see + # them without this + export PLUGIN_CORE_AVAILABLE_PATH + export DOKKU_SOURCE="${BATS_TEST_DIRNAME}/../../dokku" + run /bin/bash -c 'source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"; comm -23 <(grep -oE "[{][A-Z_]+:=" "$DOKKU_SOURCE" | tr -cd "A-Z_\n" | sort -u | grep -vx DOKKU_PID) <(fn-cli-preserved-env-names | tr " " "\n" | sort -u)' + echo "output: $output" + echo "status: $status" + assert_success + assert_output "" + unset DOKKU_SOURCE +} + @test "(common) [preserve-env] parse_args records global flags for replay" { run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; parse_args --label=a=b run foo env; echo \"\$DOKKU_GLOBAL_FLAGS\"" echo "output: $output"