diff --git a/base-notebook/start.sh b/base-notebook/start.sh index 4b306b53b6..6ab6d223be 100755 --- a/base-notebook/start.sh +++ b/base-notebook/start.sh @@ -39,6 +39,18 @@ run-hooks () { echo "${0}: done running hooks in ${1}" } +# A helper function to unset env vars listed in the value of the env var +# JUPYTER_ENV_VARS_TO_UNSET. +unset_explicit_env_vars () { + if [ -n "${JUPYTER_ENV_VARS_TO_UNSET}" ]; then + for env_var_to_unset in $(echo "${JUPYTER_ENV_VARS_TO_UNSET}" | tr ',' ' '); do + echo "Unset ${env_var_to_unset} due to JUPYTER_ENV_VARS_TO_UNSET" + unset "${env_var_to_unset}" + done + unset JUPYTER_ENV_VARS_TO_UNSET + fi +} + # NOTE: This hook will run as the user the container was started with! run-hooks /usr/local/bin/start-notebook.d @@ -143,6 +155,7 @@ if [ "$(id -u)" == 0 ] ; then # NOTE: This hook is run as the root user! run-hooks /usr/local/bin/before-notebook.d + unset_explicit_env_vars echo "Running as ${NB_USER}:" "${cmd[@]}" exec sudo --preserve-env --set-home --user "${NB_USER}" \ PATH="${PATH}" \ @@ -199,6 +212,7 @@ else # NOTE: This hook is run as the user we started the container as! run-hooks /usr/local/bin/before-notebook.d + unset_explicit_env_vars echo "Executing the command:" "${cmd[@]}" exec "${cmd[@]}" fi diff --git a/base-notebook/test/test_container_options.py b/base-notebook/test/test_container_options.py index 31e529fa81..8e49ee4149 100644 --- a/base-notebook/test/test_container_options.py +++ b/base-notebook/test/test_container_options.py @@ -240,25 +240,26 @@ def test_container_not_delete_bind_mount(container, tmp_path): assert len(list(tmp_path.iterdir())) == 1 -@pytest.mark.skip(reason="not yet implemented; TODO: cherry-pick b44b7ab") -def test_jupyter_env_vars_to_unset_as_root(container): +@pytest.mark.parametrize("enable_root", [False, True]) +def test_jupyter_env_vars_to_unset_as_root(container, enable_root): """Environment variables names listed in JUPYTER_ENV_VARS_TO_UNSET should be unset in the final environment.""" + root_args = {"user": "root"} if enable_root else {} c = container.run( tty=True, - user="root", environment=[ "JUPYTER_ENV_VARS_TO_UNSET=SECRET_ANIMAL,UNUSED_ENV,SECRET_FRUIT", "FRUIT=bananas", - "SECRET_FRUIT=mango", "SECRET_ANIMAL=cats", + "SECRET_FRUIT=mango", ], command=[ "start.sh", "bash", "-c", - "echo I like $FRUIT and ${SECRET_FRUIT:-stuff}, and love ${SECRET_LOVE:-to keep secrets}!", + "echo I like $FRUIT and ${SECRET_FRUIT:-stuff}, and love ${SECRET_ANIMAL:-to keep secrets}!", ], + **root_args, ) rv = c.wait(timeout=10) assert rv == 0 or rv["StatusCode"] == 0 diff --git a/docs/using/common.md b/docs/using/common.md index b42ecb87b6..93a9a78003 100644 --- a/docs/using/common.md +++ b/docs/using/common.md @@ -78,6 +78,8 @@ You do so by passing arguments to the `docker run` command. **You must grant the within-container notebook user or group (`NB_UID` or `NB_GID`) write access to the host directory (e.g., `sudo chown 1000 /some/host/folder/for/work`).** - `--user 5000 --group-add users` - Launches the container with a specific user ID and adds that user to the `users` group so that it can modify files in the default home directory and `/opt/conda`. You can use these arguments as alternatives to setting `${NB_UID}` and `${NB_GID}`. +- `-e JUPYTER_ENV_VARS_TO_UNSET=ADMIN_SECRET_1,ADMIN_SECRET_2` - Unsets specified environment variables in the default startup script. + The variables are unset after the hooks have executed but before the command provided to the startup script runs. ## Startup Hooks