From 3072b5012ce102351aa49b0ebafde12960e2b9d4 Mon Sep 17 00:00:00 2001 From: Daniel Weuthen Date: Tue, 1 Sep 2026 20:17:43 +0200 Subject: [PATCH 1/3] [common-utils] - Make sudoers config optional --- src/common-utils/README.md | 1 + src/common-utils/devcontainer-feature.json | 7 ++++++- src/common-utils/main.sh | 11 +++++++---- test/common-utils/scenarios.json | 18 ++++++++++++++++++ test/common-utils/sudoers-false.sh | 16 ++++++++++++++++ test/common-utils/sudoers-true.sh | 19 +++++++++++++++++++ 6 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 test/common-utils/sudoers-false.sh create mode 100644 test/common-utils/sudoers-true.sh diff --git a/src/common-utils/README.md b/src/common-utils/README.md index 3d21e8b3f..fd87c83e5 100644 --- a/src/common-utils/README.md +++ b/src/common-utils/README.md @@ -23,6 +23,7 @@ Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-r | username | Enter name of a non-root user to configure or none to skip | string | automatic | | userUid | Enter UID for non-root user | string | automatic | | userGid | Enter GID for non-root user | string | automatic | +| sudoers | Add sudoers entry for the non-root user | boolean | true | | nonFreePackages | Add packages from non-free Debian repository? (Debian only) | boolean | false | ## OS Support diff --git a/src/common-utils/devcontainer-feature.json b/src/common-utils/devcontainer-feature.json index 5b56f6184..3a14e9d44 100644 --- a/src/common-utils/devcontainer-feature.json +++ b/src/common-utils/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "common-utils", - "version": "2.5.9", + "version": "2.6.0", "name": "Common Utilities", "documentationURL": "https://github.com/devcontainers/features/tree/main/src/common-utils", "description": "Installs a set of common command line utilities, Oh My Zsh!, and sets up a non-root user.", @@ -60,6 +60,11 @@ "default": "automatic", "description": "Enter GID for non-root user" }, + "sudoers": { + "type": "boolean", + "default": true, + "description": "Add non-root user to passwordless sudoers?" + }, "nonFreePackages": { "type": "boolean", "default": false, diff --git a/src/common-utils/main.sh b/src/common-utils/main.sh index 5e5487aa2..9ddeabd7e 100644 --- a/src/common-utils/main.sh +++ b/src/common-utils/main.sh @@ -17,6 +17,7 @@ UPGRADE_PACKAGES="${UPGRADEPACKAGES:-"true"}" USERNAME="${USERNAME:-"automatic"}" USER_UID="${USERUID:-"automatic"}" USER_GID="${USERGID:-"automatic"}" +SUDOERS="${SUDOERS:-"true"}" ADD_NON_FREE_PACKAGES="${NONFREEPACKAGES:-"false"}" INSTALL_SSL="${INSTALLSSL:-"true"}" @@ -471,10 +472,12 @@ else fi # Add add sudo support for non-root user -if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then - echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME - chmod 0440 /etc/sudoers.d/$USERNAME - EXISTING_NON_ROOT_USER="${USERNAME}" +if [ "$SUDOERS" = "true" ]; then + if [ "${USERNAME}" != "root" ] && [ "${EXISTING_NON_ROOT_USER}" != "${USERNAME}" ]; then + echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME + chmod 0440 /etc/sudoers.d/$USERNAME + EXISTING_NON_ROOT_USER="${USERNAME}" + fi fi # ********************************* diff --git a/test/common-utils/scenarios.json b/test/common-utils/scenarios.json index c70c574a7..f5e35dac2 100644 --- a/test/common-utils/scenarios.json +++ b/test/common-utils/scenarios.json @@ -264,6 +264,24 @@ "common-utils": {} } }, + "sudoers-true": { + "image": "debian:bullseye", + "remoteUser": "vscode", + "features": { + "common-utils": { + "sudoers": true + } + } + }, + "sudoers-false": { + "image": "debian:bullseye", + "remoteUser": "vscode", + "features": { + "common-utils": { + "sudoers": false + } + } + }, "terminal-title-on-xterm": { "image": "node", "features": { diff --git a/test/common-utils/sudoers-false.sh b/test/common-utils/sudoers-false.sh new file mode 100644 index 000000000..8b08ffe26 --- /dev/null +++ b/test/common-utils/sudoers-false.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Always run these checks as the non-root user +user="$(whoami)" +check "user" grep vscode <<< "$user" + +# Check that the sudoers file for the non-root user does not exist +check "sudoers file does not exist" test ! -f /etc/sudoers.d/$user + +# Report result +reportResults diff --git a/test/common-utils/sudoers-true.sh b/test/common-utils/sudoers-true.sh new file mode 100644 index 000000000..92b8399c3 --- /dev/null +++ b/test/common-utils/sudoers-true.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Always run these checks as the non-root user +user="$(whoami)" +check "user" grep vscode <<< "$user" + +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$user + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$user ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$user + +# Report result +reportResults From 6a16cfb8bea1829a0bd07549652f7f8dbc1b4007 Mon Sep 17 00:00:00 2001 From: Daniel Weuthen Date: Mon, 14 Sep 2026 11:57:39 +0200 Subject: [PATCH 2/3] remove/relace debian bullseye (EOL) with trixie --- test/common-utils/bullseye.sh | 14 -------------- test/common-utils/scenarios.json | 27 ++++++++++++++++++--------- 2 files changed, 18 insertions(+), 23 deletions(-) delete mode 100755 test/common-utils/bullseye.sh diff --git a/test/common-utils/bullseye.sh b/test/common-utils/bullseye.sh deleted file mode 100755 index 5a396a7f4..000000000 --- a/test/common-utils/bullseye.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -e - -# Optional: Import test library -source dev-container-features-test-lib - -# Definition specific tests -. /etc/os-release -check "non-root user" test "$(whoami)" = "devcontainer" -check "distro" test "${VERSION_CODENAME}" = "bullseye" - -# Report result -reportResults \ No newline at end of file diff --git a/test/common-utils/scenarios.json b/test/common-utils/scenarios.json index f5e35dac2..ada05945a 100644 --- a/test/common-utils/scenarios.json +++ b/test/common-utils/scenarios.json @@ -12,14 +12,14 @@ "features": { "common-utils": {} } - }, - "bullseye": { - "image": "debian:bullseye", + }, + "resolute": { + "image": "ubuntu:resolute", "remoteUser": "devcontainer", "features": { "common-utils": {} } - }, + }, "bookworm": { "image": "debian:bookworm", "remoteUser": "devcontainer", @@ -29,6 +29,15 @@ } } }, + "trixie": { + "image": "debian:trixie", + "remoteUser": "devcontainer", + "features": { + "common-utils": { + "nonFreePackages": "true" + } + } + }, "centos-7": { "image": "centos:7", "remoteUser": "devcontainer", @@ -114,7 +123,7 @@ } }, "alternate-values": { - "image": "debian:bullseye", + "image": "debian:trixie", "features": { "common-utils": { "username": "alternate", @@ -127,7 +136,7 @@ } }, "username-default": { - "image": "debian:bullseye", + "image": "debian:trixie", "features": { "common-utils": {} } @@ -166,7 +175,7 @@ } }, "configure_zsh_no_template_first_step": { - "image": "debian:bullseye", + "image": "debian:trixie", "remoteUser": "devcontainer", "features": { "common-utils": { @@ -265,7 +274,7 @@ } }, "sudoers-true": { - "image": "debian:bullseye", + "image": "debian:trixie", "remoteUser": "vscode", "features": { "common-utils": { @@ -274,7 +283,7 @@ } }, "sudoers-false": { - "image": "debian:bullseye", + "image": "debian:trixie", "remoteUser": "vscode", "features": { "common-utils": { From 7fe44f1e4d77a08ce586fbaf8467c3fc869f8aed Mon Sep 17 00:00:00 2001 From: Daniel Weuthen Date: Mon, 14 Sep 2026 11:58:22 +0200 Subject: [PATCH 3/3] add sudeoers test for other distributions (except centos-7) --- test/common-utils/bionic.sh | 6 +++ test/common-utils/bookworm.sh | 6 +++ test/common-utils/devcontainer-info.sh | 6 +++ test/common-utils/fedora.sh | 6 +++ test/common-utils/focal.sh | 6 +++ test/common-utils/jammy.sh | 6 +++ test/common-utils/noble.sh | 6 +++ test/common-utils/resolute.sh | 22 +++++++++++ test/common-utils/trixie.sh | 51 ++++++++++++++++++++++++++ 9 files changed, 115 insertions(+) create mode 100755 test/common-utils/resolute.sh create mode 100755 test/common-utils/trixie.sh diff --git a/test/common-utils/bionic.sh b/test/common-utils/bionic.sh index 349b4c32d..79c9602bc 100755 --- a/test/common-utils/bionic.sh +++ b/test/common-utils/bionic.sh @@ -10,5 +10,11 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "bionic" +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/bookworm.sh b/test/common-utils/bookworm.sh index db8628713..a0129ba8b 100755 --- a/test/common-utils/bookworm.sh +++ b/test/common-utils/bookworm.sh @@ -41,5 +41,11 @@ checkCommon check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "bookworm" +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/devcontainer-info.sh b/test/common-utils/devcontainer-info.sh index 65a4a40fb..e81218a1d 100755 --- a/test/common-utils/devcontainer-info.sh +++ b/test/common-utils/devcontainer-info.sh @@ -21,5 +21,11 @@ check_info "revision" check_info "time" check_info "url" +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults diff --git a/test/common-utils/fedora.sh b/test/common-utils/fedora.sh index e52f99bff..9bbbabd22 100755 --- a/test/common-utils/fedora.sh +++ b/test/common-utils/fedora.sh @@ -13,5 +13,11 @@ check "jq" jq --version check "bubblewrap" bwrap --version check "socat" socat -V +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" sudo test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/focal.sh b/test/common-utils/focal.sh index 28d8b8bcc..d8b31d96d 100755 --- a/test/common-utils/focal.sh +++ b/test/common-utils/focal.sh @@ -10,5 +10,11 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "focal" +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/jammy.sh b/test/common-utils/jammy.sh index e09765168..ee54b4f4b 100755 --- a/test/common-utils/jammy.sh +++ b/test/common-utils/jammy.sh @@ -12,5 +12,11 @@ check "distro" test "${VERSION_CODENAME}" = "jammy" check "bubblewrap" bwrap --version check "socat" socat -V +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/noble.sh b/test/common-utils/noble.sh index e1d578271..d2903664a 100644 --- a/test/common-utils/noble.sh +++ b/test/common-utils/noble.sh @@ -12,6 +12,12 @@ check "distro" test "${VERSION_CODENAME}" = "noble" check "bubblewrap" bwrap --version check "socat" socat -V +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + # Report result reportResults diff --git a/test/common-utils/resolute.sh b/test/common-utils/resolute.sh new file mode 100755 index 000000000..e97462586 --- /dev/null +++ b/test/common-utils/resolute.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +# Definition specific tests +. /etc/os-release +check "non-root user" test "$(whoami)" = "devcontainer" +check "distro" test "${VERSION_CODENAME}" = "resolute" +check "bubblewrap" bwrap --version +check "socat" socat -V + +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + +# Report result +reportResults \ No newline at end of file diff --git a/test/common-utils/trixie.sh b/test/common-utils/trixie.sh new file mode 100755 index 000000000..67279e391 --- /dev/null +++ b/test/common-utils/trixie.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +set -e + +# Optional: Import test library +source dev-container-features-test-lib + +FAILED=() +echoStderr() +{ + echo "$@" 1>&2 +} + +checkOSPackages() { + LABEL=$1 + shift + echo -e "\n🧪 Testing $LABEL" + if dpkg-query --show -f='${Package}: ${Version}\n' "$@"; then + echo "✅ Passed!" + return 0 + else + echoStderr "❌ $LABEL check failed." + FAILED+=("$LABEL") + return 1 + fi +} + +checkCommon() +{ + PACKAGE_LIST="manpages-posix \ + manpages-posix-dev" + + checkOSPackages "Installation of manpages-posix and manpages-posix-dev (non-free)" ${PACKAGE_LIST} +} + +# Check for manpages-posix, manpages-posix-dev non-free packages +checkCommon + +# Definition specific tests +. /etc/os-release +check "non-root user" test "$(whoami)" = "devcontainer" +check "distro" test "${VERSION_CODENAME}" = "trixie" + +# Check if the sudoers file for the non-root user exists +check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) + +# Check if the sudoers entry for the non-root user is correctly configured +check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD:ALL" /etc/sudoers.d/$(whoami) + +# Report result +reportResults \ No newline at end of file