From 76776d6e2ba9b3eb26479f4a8c2daf0a0d0a11c3 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Fri, 9 Oct 2026 13:58:52 +0200 Subject: [PATCH] common-utils: Add sandboxing dependencies and distro coverage Install slirp4netns, util-linux, and iptables alongside bubblewrap. Handle optional RPM packages with microdnf repoquery support, and verify sandbox commands across the configured distro/version scenarios. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/common-utils/NOTES.md | 5 +++ src/common-utils/devcontainer-feature.json | 2 +- src/common-utils/main.sh | 33 +++++++++++++++++--- test/common-utils/Azure-linux-CU.sh | 10 ++++++ test/common-utils/alma-8-minimal.sh | 4 +++ test/common-utils/alma-8.sh | 4 +++ test/common-utils/alma-9-minimal.sh | 4 +++ test/common-utils/alma-9.sh | 3 ++ test/common-utils/alpine-3-14.sh | 4 +++ test/common-utils/alpine-3-15.sh | 4 +++ test/common-utils/alpine-3-18.sh | 4 +++ test/common-utils/alpine-base-zsh-default.sh | 4 +++ test/common-utils/alpine.sh | 3 ++ test/common-utils/bookworm.sh | 4 +++ test/common-utils/centos-7.sh | 4 +++ test/common-utils/fedora.sh | 3 ++ test/common-utils/jammy.sh | 3 ++ test/common-utils/mariner.sh | 10 ++++++ test/common-utils/noble.sh | 4 ++- test/common-utils/resolute.sh | 3 ++ test/common-utils/rocky-8-minimal.sh | 4 +++ test/common-utils/rocky-8.sh | 4 +++ test/common-utils/rocky-9-minimal.sh | 4 +++ test/common-utils/rocky-9.sh | 3 ++ test/common-utils/test.sh | 3 ++ test/common-utils/trixie.sh | 4 +++ test/common-utils/ubi-8.sh | 10 ++++++ 27 files changed, 140 insertions(+), 7 deletions(-) diff --git a/src/common-utils/NOTES.md b/src/common-utils/NOTES.md index 9faa2eedd..041743887 100644 --- a/src/common-utils/NOTES.md +++ b/src/common-utils/NOTES.md @@ -7,8 +7,13 @@ This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise In addition to the common CLI tools (curl, wget, git, jq, nano, vim, etc.), this Feature installs: - **bubblewrap** (`bwrap`) — a lightweight sandboxing tool used as a dependency by some desktop and container tooling. +- **slirp4netns** - user-mode networking for unprivileged network namespaces. +- **util-linux** - system utilities, including `unshare`, for working with Linux namespaces. +- **iptables** - tools for configuring packet filtering and NAT rules used by sandbox networking. - **socat** — a multipurpose relay for bidirectional data transfer between two independent data channels (e.g., sockets, files, pipes). +On RPM-based distributions, bubblewrap and slirp4netns are installed only when available in the configured repositories. + ## Using with dev container images This Feature is used in many of the [dev container images](https://github.com/search?q=repo%3Adevcontainers%2Fimages+%22ghcr.io%2Fdevcontainers%2Ffeatures%2Fcommon-utils%22&type=code), as a result diff --git a/src/common-utils/devcontainer-feature.json b/src/common-utils/devcontainer-feature.json index 009c22e68..6f7d890e1 100644 --- a/src/common-utils/devcontainer-feature.json +++ b/src/common-utils/devcontainer-feature.json @@ -1,6 +1,6 @@ { "id": "common-utils", - "version": "2.7.0", + "version": "2.7.1", "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.", diff --git a/src/common-utils/main.sh b/src/common-utils/main.sh index 4cb2b103d..200687920 100644 --- a/src/common-utils/main.sh +++ b/src/common-utils/main.sh @@ -78,6 +78,9 @@ install_debian_packages() { manpages-dev \ init-system-helpers \ bubblewrap \ + slirp4netns \ + util-linux \ + iptables \ socat" if [ "${INSTALL_SSL}" = "true" ]; then @@ -219,13 +222,10 @@ install_redhat_packages() { which \ man-db \ strace \ + util-linux \ + iptables \ socat" - # Install bubblewrap if available (not present in UBI repositories) - if ${install_cmd} -q list bubblewrap >/dev/null 2>&1; then - package_list="${package_list} bubblewrap" - fi - # rockylinux:9 installs 'curl-minimal' which clashes with 'curl' # Install 'curl' for every OS except this rockylinux:9 if [[ "${ID}" = "rocky" ]] && [[ "${VERSION}" != *"9."* ]]; then @@ -253,6 +253,26 @@ install_redhat_packages() { remove_epel="true" fi + # Sandboxing packages are not available in all RPM repositories. + local sandbox_package sandbox_package_info sandbox_package_available + for sandbox_package in bubblewrap slirp4netns; do + sandbox_package_available="false" + if [ "${install_cmd}" = "microdnf" ]; then + sandbox_package_info="$(${install_cmd} repoquery "${sandbox_package}")" + if grep -q "^${sandbox_package}-" <<< "${sandbox_package_info}"; then + sandbox_package_available="true" + fi + elif ${install_cmd} -q list "${sandbox_package}" >/dev/null 2>&1; then + sandbox_package_available="true" + fi + + if [ "${sandbox_package_available}" = "true" ]; then + package_list="${package_list} ${sandbox_package}" + else + echo "Skipping ${sandbox_package}: not available in the configured repositories." + fi + done + # Install zsh if needed if [ "${INSTALL_ZSH}" = "true" ] && ! type zsh > /dev/null 2>&1; then package_list="${package_list} zsh" @@ -330,6 +350,9 @@ install_alpine_packages() { shadow \ strace \ bubblewrap \ + slirp4netns \ + util-linux \ + iptables \ socat" # # Include libssl1.1 if available (not available for 3.19 and newer) diff --git a/test/common-utils/Azure-linux-CU.sh b/test/common-utils/Azure-linux-CU.sh index eeba25d10..ad83708ea 100644 --- a/test/common-utils/Azure-linux-CU.sh +++ b/test/common-utils/Azure-linux-CU.sh @@ -17,6 +17,16 @@ check "azurelinux distro" test "$ID" = "azurelinux" # Definition specific tests check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "util-linux" unshare --version +check "iptables" iptables --version + +available_packages="$(tdnf -q list)" +if grep -q '^slirp4netns\.' <<< "${available_packages}"; then + check "slirp4netns" slirp4netns --version +else + echo "Skipping slirp4netns: not available in the configured repositories." +fi # Report result reportResults diff --git a/test/common-utils/alma-8-minimal.sh b/test/common-utils/alma-8-minimal.sh index d08731824..fbfc2ea51 100755 --- a/test/common-utils/alma-8-minimal.sh +++ b/test/common-utils/alma-8-minimal.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el8" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alma-8.sh b/test/common-utils/alma-8.sh index d08731824..fbfc2ea51 100755 --- a/test/common-utils/alma-8.sh +++ b/test/common-utils/alma-8.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el8" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alma-9-minimal.sh b/test/common-utils/alma-9-minimal.sh index cb2b339e1..41c2792b5 100755 --- a/test/common-utils/alma-9-minimal.sh +++ b/test/common-utils/alma-9-minimal.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el9" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alma-9.sh b/test/common-utils/alma-9.sh index c0771df14..e503fec18 100755 --- a/test/common-utils/alma-9.sh +++ b/test/common-utils/alma-9.sh @@ -12,6 +12,9 @@ check "distro" test "${PLATFORM_ID}" = "platform:el9" check "curl" curl --version check "jq" jq --version check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Report result diff --git a/test/common-utils/alpine-3-14.sh b/test/common-utils/alpine-3-14.sh index 5ed334c61..953b2cf51 100755 --- a/test/common-utils/alpine-3-14.sh +++ b/test/common-utils/alpine-3-14.sh @@ -10,6 +10,10 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "alpine" check "bashrc" ls /etc/bash/bashrc +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alpine-3-15.sh b/test/common-utils/alpine-3-15.sh index 5ed334c61..953b2cf51 100755 --- a/test/common-utils/alpine-3-15.sh +++ b/test/common-utils/alpine-3-15.sh @@ -10,6 +10,10 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "alpine" check "bashrc" ls /etc/bash/bashrc +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alpine-3-18.sh b/test/common-utils/alpine-3-18.sh index eaf384b9e..cb6ff5475 100755 --- a/test/common-utils/alpine-3-18.sh +++ b/test/common-utils/alpine-3-18.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "alpine" check "bashrc" ls /etc/bash/bashrc check "libssl1.1 is installed" grep "libssl1.1" <(apk list --no-cache libssl1.1) +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/alpine-base-zsh-default.sh b/test/common-utils/alpine-base-zsh-default.sh index 9fc00a267..7c57daf2f 100644 --- a/test/common-utils/alpine-base-zsh-default.sh +++ b/test/common-utils/alpine-base-zsh-default.sh @@ -8,6 +8,10 @@ source dev-container-features-test-lib # Definition specific tests check "alpine default shell zsh" \ bash -c "getent passwd $(whoami) | awk -F : '{ print $7 }' | grep '/bin/zsh'" +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults diff --git a/test/common-utils/alpine.sh b/test/common-utils/alpine.sh index f60732527..80c253995 100755 --- a/test/common-utils/alpine.sh +++ b/test/common-utils/alpine.sh @@ -10,6 +10,9 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "alpine" check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Report result diff --git a/test/common-utils/bookworm.sh b/test/common-utils/bookworm.sh index a0129ba8b..34f575331 100755 --- a/test/common-utils/bookworm.sh +++ b/test/common-utils/bookworm.sh @@ -40,6 +40,10 @@ checkCommon . /etc/os-release check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "bookworm" +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Check if the sudoers file for the non-root user exists check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) diff --git a/test/common-utils/centos-7.sh b/test/common-utils/centos-7.sh index 69f01d1ed..966044a60 100755 --- a/test/common-utils/centos-7.sh +++ b/test/common-utils/centos-7.sh @@ -10,6 +10,10 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_ID}" = "7" check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/fedora.sh b/test/common-utils/fedora.sh index 9bbbabd22..89d83e88e 100755 --- a/test/common-utils/fedora.sh +++ b/test/common-utils/fedora.sh @@ -11,6 +11,9 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "fedora" check "jq" jq --version check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Check if the sudoers file for the non-root user exists diff --git a/test/common-utils/jammy.sh b/test/common-utils/jammy.sh index ee54b4f4b..c9c448d99 100755 --- a/test/common-utils/jammy.sh +++ b/test/common-utils/jammy.sh @@ -10,6 +10,9 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "jammy" check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Check if the sudoers file for the non-root user exists diff --git a/test/common-utils/mariner.sh b/test/common-utils/mariner.sh index b0d2c91e4..f6aeb69f0 100755 --- a/test/common-utils/mariner.sh +++ b/test/common-utils/mariner.sh @@ -10,6 +10,16 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${ID}" = "mariner" check "jq" jq --version +check "bubblewrap" bwrap --version +check "util-linux" unshare --version +check "iptables" iptables --version + +available_packages="$(sudo tdnf -q list)" +if grep -q '^slirp4netns\.' <<< "${available_packages}"; then + check "slirp4netns" slirp4netns --version +else + echo "Skipping slirp4netns: not available in the configured repositories." +fi # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/noble.sh b/test/common-utils/noble.sh index d2903664a..1baf7de06 100644 --- a/test/common-utils/noble.sh +++ b/test/common-utils/noble.sh @@ -10,6 +10,9 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "noble" check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Check if the sudoers file for the non-root user exists @@ -20,4 +23,3 @@ check "sudoers entry for non-root user" sudo grep "$(whoami) ALL=(root) NOPASSWD # Report result reportResults - diff --git a/test/common-utils/resolute.sh b/test/common-utils/resolute.sh index e97462586..f28ef5363 100755 --- a/test/common-utils/resolute.sh +++ b/test/common-utils/resolute.sh @@ -10,6 +10,9 @@ source dev-container-features-test-lib check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "resolute" check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Check if the sudoers file for the non-root user exists diff --git a/test/common-utils/rocky-8-minimal.sh b/test/common-utils/rocky-8-minimal.sh index d08731824..fbfc2ea51 100755 --- a/test/common-utils/rocky-8-minimal.sh +++ b/test/common-utils/rocky-8-minimal.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el8" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/rocky-8.sh b/test/common-utils/rocky-8.sh index d08731824..fbfc2ea51 100755 --- a/test/common-utils/rocky-8.sh +++ b/test/common-utils/rocky-8.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el8" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/rocky-9-minimal.sh b/test/common-utils/rocky-9-minimal.sh index cb2b339e1..41c2792b5 100755 --- a/test/common-utils/rocky-9-minimal.sh +++ b/test/common-utils/rocky-9-minimal.sh @@ -11,6 +11,10 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el9" check "curl" curl --version check "jq" jq --version +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Report result reportResults \ No newline at end of file diff --git a/test/common-utils/rocky-9.sh b/test/common-utils/rocky-9.sh index c0771df14..e503fec18 100755 --- a/test/common-utils/rocky-9.sh +++ b/test/common-utils/rocky-9.sh @@ -12,6 +12,9 @@ check "distro" test "${PLATFORM_ID}" = "platform:el9" check "curl" curl --version check "jq" jq --version check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V # Report result diff --git a/test/common-utils/test.sh b/test/common-utils/test.sh index 46cb119be..8f4181a1a 100755 --- a/test/common-utils/test.sh +++ b/test/common-utils/test.sh @@ -11,6 +11,9 @@ check "curl" curl --version check "git" git --version check "zsh" zsh --version check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version check "socat" socat -V check "ps" ps --version check "Oh My Zsh! theme" test -e $HOME/.oh-my-zsh/custom/themes/devcontainers.zsh-theme diff --git a/test/common-utils/trixie.sh b/test/common-utils/trixie.sh index 67279e391..39c995a60 100755 --- a/test/common-utils/trixie.sh +++ b/test/common-utils/trixie.sh @@ -40,6 +40,10 @@ checkCommon . /etc/os-release check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${VERSION_CODENAME}" = "trixie" +check "bubblewrap" bwrap --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version # Check if the sudoers file for the non-root user exists check "sudoers file exists" test -f /etc/sudoers.d/$(whoami) diff --git a/test/common-utils/ubi-8.sh b/test/common-utils/ubi-8.sh index d97e614a7..c24ab6786 100644 --- a/test/common-utils/ubi-8.sh +++ b/test/common-utils/ubi-8.sh @@ -11,6 +11,16 @@ check "non-root user" test "$(whoami)" = "devcontainer" check "distro" test "${PLATFORM_ID}" = "platform:el8" check "curl" curl --version check "jq" jq --version +check "slirp4netns" slirp4netns --version +check "util-linux" unshare --version +check "iptables" iptables --version + +available_packages="$(sudo dnf -q list)" +if grep -q '^bubblewrap\.' <<< "${available_packages}"; then + check "bubblewrap" bwrap --version +else + echo "Skipping bubblewrap: not available in the configured repositories." +fi # Report result reportResults