From f06a819230cf3e9b8f2fb607bf899bf405686a2d Mon Sep 17 00:00:00 2001 From: Dalibor Kricka Date: Fri, 15 Aug 2025 13:05:52 +0200 Subject: [PATCH 1/3] cmd/create, cmd/run: Warning message when using non-Toolbx image Prompt users if they want to continue creating or running a Toolbox container with an image that is not Toolbox-verified. Verified images are guaranteed to work with Toolbx because they were previously tested. Such an image contains at least one of these labels (see https://containertoolbx.org/doc/): - com.github.containers.toolbox="true" - com.github.debarshiray.toolbox="true" https://github.com/containers/toolbox/issues/1622 --- src/cmd/create.go | 11 +++++++++++ src/cmd/run.go | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/cmd/create.go b/src/cmd/create.go index 531721b..de40626 100644 --- a/src/cmd/create.go +++ b/src/cmd/create.go @@ -241,6 +241,17 @@ func createContainer(container, image, release, authFile string, showCommandToEn } } + if !rootFlags.assumeYes { + if isToolboxImage, err := podman.IsToolboxImage(imageFull); err != nil { + return fmt.Errorf("failed to verify image compatibility: %w", err) + } else if !isToolboxImage { + prompt := fmt.Sprintf("Image '%s' is not a Toolbx image and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]:", imageFull) + if !askForConfirmation(prompt) { + return nil + } + } + } + var toolbxDelayEntryPointEnv []string if toolbxDelayEntryPoint, ok := os.LookupEnv("TOOLBX_DELAY_ENTRY_POINT"); ok { diff --git a/src/cmd/run.go b/src/cmd/run.go index 389ea16..3bcfbd8 100644 --- a/src/cmd/run.go +++ b/src/cmd/run.go @@ -183,6 +183,8 @@ func runCommand(container string, } } + checkImageCompatibility := true + logrus.Debugf("Checking if container %s exists", container) if _, err := podman.ContainerExists(container); err != nil { @@ -225,6 +227,10 @@ func runCommand(container string, if err := createContainer(container, image, release, "", false); err != nil { return err } + + // set to false -> check was already made when creating container during toolbx enter + checkImageCompatibility = false + } else if containersCount == 1 && defaultContainer { fmt.Fprintf(os.Stderr, "Error: container %s not found\n", container) @@ -249,6 +255,19 @@ func runCommand(container string, return fmt.Errorf("failed to inspect container %s", container) } + if checkImageCompatibility && !rootFlags.assumeYes { + imageFull := containerObj.Image() + + if isToolboxImage, err := podman.IsToolboxImage(imageFull); err != nil { + logrus.Debugf("Failed to verify image '%s' compatibility for container '%s': %s", imageFull, container, err) + } else if !isToolboxImage { + prompt := fmt.Sprintf("Container '%s' uses a non-Toolbx image '%s' and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]:", container, imageFull) + if !askForConfirmation(prompt) { + return nil + } + } + } + entryPoint := containerObj.EntryPoint() entryPointPID := containerObj.EntryPointPID() logrus.Debugf("Entry point of container %s is %s (PID=%d)", container, entryPoint, entryPointPID) From 38e8d047d1486e896fb26ba2d1613a57b5148903 Mon Sep 17 00:00:00 2001 From: Dalibor Kricka Date: Fri, 15 Aug 2025 13:11:29 +0200 Subject: [PATCH 2/3] pkg/podman/podman, cmd/rmi: Change return values of IsToolboxImage() The original version of the IsToolboxImage() function in pkg/podman/podman.go returned an error when an image was not compatible with Toolbx. The new version returns 'false' without error on a non-Toolbx container, so it can be distinguished when the image inspection actually fails. This new behavior is used in detecting such images when creating or running Toolbx containers: f06a819 --- src/cmd/rmi.go | 5 ++++- src/pkg/podman/podman.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cmd/rmi.go b/src/cmd/rmi.go index f10b33d..50bcffe 100644 --- a/src/cmd/rmi.go +++ b/src/cmd/rmi.go @@ -90,9 +90,12 @@ func rmi(cmd *cobra.Command, args []string) error { } for _, image := range args { - if _, err := podman.IsToolboxImage(image); err != nil { + if isToolboxImage, err := podman.IsToolboxImage(image); err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err) continue + } else if !isToolboxImage { + fmt.Fprintf(os.Stderr, "Error: %s is not a Toolbx image\n", image) + continue } if err := podman.RemoveImage(image, rmiFlags.forceDelete); err != nil { diff --git a/src/pkg/podman/podman.go b/src/pkg/podman/podman.go index 4711b8b..297e903 100644 --- a/src/pkg/podman/podman.go +++ b/src/pkg/podman/podman.go @@ -352,12 +352,12 @@ func IsToolboxImage(image string) (bool, error) { } if info["Labels"] == nil { - return false, fmt.Errorf("%s is not a Toolbx image", image) + return false, nil } labels := info["Labels"].(map[string]interface{}) if labels["com.github.containers.toolbox"] != "true" && labels["com.github.debarshiray.toolbox"] != "true" { - return false, fmt.Errorf("%s is not a Toolbx image", image) + return false, nil } return true, nil From f3f59b3b780ce5b2b480789699e1ac81e212837d Mon Sep 17 00:00:00 2001 From: Dalibor Kricka Date: Fri, 15 Aug 2025 13:18:14 +0200 Subject: [PATCH 3/3] test/system: Added test cases for non-Toolbx image usage warning Test cases for non-Toolbx image usage warning added in the commit f06a819 --- test/system/101-create.bats | 53 +++++++++++++++++++++++++++++++++++ test/system/104-run.bats | 47 +++++++++++++++++++++++++++++++ test/system/105-enter.bats | 47 +++++++++++++++++++++++++++++++ test/system/libs/helpers.bash | 37 ++++++++++++++++++++++++ 4 files changed, 184 insertions(+) diff --git a/test/system/101-create.bats b/test/system/101-create.bats index db7c765..689bc60 100644 --- a/test/system/101-create.bats +++ b/test/system/101-create.bats @@ -1009,3 +1009,56 @@ teardown() { assert [ ${#lines[@]} -eq 2 ] assert [ ${#stderr_lines[@]} -eq 0 ] } + +@test "create: With a non-Toolbx image and prompt for confirmation - Yes" { + image="$(build_non_toolbx_image)" + containerName="test-container-non-toolbx" + + run --keep-empty-lines --separate-stderr "$TOOLBX" create --image "$image" "$containerName" <<< "y" + + assert_success + assert_line --index 0 "Image '$image' is not a Toolbx image and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: Created container: $containerName" + assert_line --index 1 "Enter with: toolbox enter $containerName" + assert [ ${#lines[@]} -eq 2 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run podman ps --all + + assert_success + assert_output --regexp "Created[[:blank:]]+$containerName" +} + +@test "create: With a non-Toolbx image and prompt for confirmation - No" { + image="$(build_non_toolbx_image)" + containerName="test-container-non-toolbx" + + run --keep-empty-lines --separate-stderr "$TOOLBX" create --image "$image" "$containerName" <<< "n" + + assert_success + assert_line --index 0 "Image '$image' is not a Toolbx image and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: " + assert [ ${#lines[@]} -eq 1 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run podman ps --all + + assert_success + assert [ ${#lines[@]} -eq 1 ] +} + +@test "create: With a non-Toolbx image and prompt for confirmation - assumeyes" { + image="$(build_non_toolbx_image)" + containerName="test-container-non-toolbx" + + run --keep-empty-lines --separate-stderr "$TOOLBX" create --assumeyes --image "$image" "$containerName" + + assert_success + assert_line --index 0 "Created container: $containerName" + assert_line --index 1 "Enter with: toolbox enter $containerName" + assert [ ${#lines[@]} -eq 2 ] + assert [ ${#stderr_lines[@]} -eq 0 ] + + run podman ps --all + + assert_success + assert_output --regexp "Created[[:blank:]]+$containerName" +} diff --git a/test/system/104-run.bats b/test/system/104-run.bats index 3883dee..32d18b4 100644 --- a/test/system/104-run.bats +++ b/test/system/104-run.bats @@ -863,3 +863,50 @@ teardown() { assert_line --index 1 "Recreate it with Toolbx version 0.0.17 or newer." assert [ ${#stderr_lines[@]} -eq 2 ] } + +@test "run: With a non-Toolbx image and prompt for confirmation - Yes" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run --container "$containerName" true <<< "y" + + assert_failure + assert_line --index 0 "Container '$containerName' uses a non-Toolbx image '$image' and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: " + assert [ ${#lines[@]} -eq 1 ] + + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to start container $containerName" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "run: With a non-Toolbx image and prompt for confirmation - No" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" run --container "$containerName" true <<< "n" + + assert_success + assert_line --index 0 "Container '$containerName' uses a non-Toolbx image '$image' and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: " + assert [ ${#lines[@]} -eq 1 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "run: With a non-Toolbx image and prompt for confirmation - assumeyes" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" --assumeyes run --container "$containerName" true + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to start container $containerName" + assert [ ${#stderr_lines[@]} -eq 1 ] +} diff --git a/test/system/105-enter.bats b/test/system/105-enter.bats index 6ff900e..c56e744 100644 --- a/test/system/105-enter.bats +++ b/test/system/105-enter.bats @@ -147,6 +147,53 @@ teardown() { assert [ ${#lines[@]} -eq 3 ] } +@test "enter: With a non-Toolbx image and prompt for confirmation - Yes" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" enter --container "$containerName" <<< "y" + + assert_failure + assert_line --index 0 "Container '$containerName' uses a non-Toolbx image '$image' and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: " + assert [ ${#lines[@]} -eq 1 ] + + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to start container $containerName" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + +@test "enter: With a non-Toolbx image and prompt for confirmation - No" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" enter --container "$containerName" <<< "n" + + assert_success + assert_line --index 0 "Container '$containerName' uses a non-Toolbx image '$image' and may not work properly (see https://containertoolbx.org/doc/). Continue anyway? [y/N]: " + assert [ ${#lines[@]} -eq 1 ] + assert [ ${#stderr_lines[@]} -eq 0 ] +} + +@test "enter: With a non-Toolbx image and prompt for confirmation - assumeyes" { + containerName="test-container-non-toolbx" + image="$(build_non_toolbx_image)" + + create_image_container "$image" "$containerName" + + run --keep-empty-lines --separate-stderr "$TOOLBX" --assumeyes enter --container "$containerName" + + assert_failure + assert [ ${#lines[@]} -eq 0 ] + + lines=("${stderr_lines[@]}") + assert_line --index 0 "Error: failed to start container $containerName" + assert [ ${#stderr_lines[@]} -eq 1 ] +} + # TODO: Write the test @test "enter: Enter the default Toolbx" { skip "Testing of entering Toolbxes is not implemented" diff --git a/test/system/libs/helpers.bash b/test/system/libs/helpers.bash index 33b42ea..4446eb3 100644 --- a/test/system/libs/helpers.bash +++ b/test/system/libs/helpers.bash @@ -255,6 +255,25 @@ function build_image_without_name() { } +function build_non_toolbx_image() { + local image_name="localhost/non-toolbx:test-$$" + + echo -e "FROM scratch\n\nLABEL test=\"non-toolbx\"" > "$BATS_TEST_TMPDIR"/Containerfile + + run podman build --quiet --tag "$image_name" "$BATS_TEST_TMPDIR" + + assert_success + assert_line --index 0 --regexp "^[a-f0-9]{64}$" + + # shellcheck disable=SC2154 + assert [ ${#lines[@]} -eq 1 ] + + rm -f "$BATS_TEST_TMPDIR"/Containerfile + + echo "$image_name" +} + + function check_bats_version() { local required_version required_version="$1" @@ -422,6 +441,24 @@ function create_default_container() { } +# Creates a container with specific name and image +# +# Parameters: +# =========== +# - image - name of the image +# - container_name - name of the container +function create_image_container() { + local image + local container_name + + image="$1" + container_name="$2" + + "$TOOLBX" --assumeyes create --container "${container_name}" --image "${image}" >/dev/null \ + || fail "Toolbx couldn't create container '$container_name'" +} + + function start_container() { local container_name container_name="$1"