From a1402d5b6bc4737655c3dcac956c3d91714feb3d Mon Sep 17 00:00:00 2001 From: Alex Pyrgiotis Date: Wed, 26 Feb 2025 17:50:18 +0200 Subject: [PATCH] Fix a Podman regression regarding Buildkit images Loading an image built with Buildkit in Podman 3.4 messes up its name. The tag somehow becomes the name of the loaded image. We know that older Podman versions are not generally affected, since Podman v3.0.1 on Debian Bullseye works properly. Also, Podman v4.0 is not affected, so it makes sense to target only Podman v3.4 for a fix. The fix is simple, tag the image properly based on the expected tag from `share/image-id.txt` and delete the incorrect tag. Refs containers/podman#16490 --- dangerzone/container_utils.py | 71 +++++++++++++++------- dangerzone/isolation_provider/container.py | 1 + tests/isolation_provider/test_container.py | 4 ++ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/dangerzone/container_utils.py b/dangerzone/container_utils.py index 0b43c96..d651f0a 100644 --- a/dangerzone/container_utils.py +++ b/dangerzone/container_utils.py @@ -95,18 +95,26 @@ def list_image_tags() -> List[str]: ) +def add_image_tag(image_id: str, new_tag: str) -> None: + """Add a tag to the Dangerzone image.""" + log.debug(f"Adding tag '{new_tag}' to image '{image_id}'") + subprocess.check_output( + [get_runtime(), "tag", image_id, new_tag], + startupinfo=get_subprocess_startupinfo(), + ) + + def delete_image_tag(tag: str) -> None: """Delete a Dangerzone image tag.""" - name = CONTAINER_NAME + ":" + tag - log.warning(f"Deleting old container image: {name}") + log.warning(f"Deleting old container image: {tag}") try: subprocess.check_output( - [get_runtime(), "rmi", "--force", name], + [get_runtime(), "rmi", "--force", tag], startupinfo=get_subprocess_startupinfo(), ) except Exception as e: log.warning( - f"Couldn't delete old container image '{name}', so leaving it there." + f"Couldn't delete old container image '{tag}', so leaving it there." f" Original error: {e}" ) @@ -120,22 +128,43 @@ def get_expected_tag() -> str: def load_image_tarball() -> None: log.info("Installing Dangerzone container image...") tarball_path = get_resource_path("container.tar") - with open(tarball_path) as f: - try: - subprocess.run( - [get_runtime(), "load"], - stdin=f, - startupinfo=get_subprocess_startupinfo(), - capture_output=True, - check=True, - ) - except subprocess.CalledProcessError as e: - if e.stderr: - error = e.stderr.decode() - else: - error = "No output" - raise errors.ImageInstallationException( - f"Could not install container image: {error}" - ) + try: + res = subprocess.run( + [get_runtime(), "load", "-i", tarball_path], + startupinfo=get_subprocess_startupinfo(), + capture_output=True, + check=True, + ) + except subprocess.CalledProcessError as e: + if e.stderr: + error = e.stderr.decode() + else: + error = "No output" + raise errors.ImageInstallationException( + f"Could not install container image: {error}" + ) + + # Loading an image built with Buildkit in Podman 3.4 messes up its name. The tag + # somehow becomes the name of the loaded image [1]. + # + # We know that older Podman versions are not generally affected, since Podman v3.0.1 + # on Debian Bullseye works properly. Also, Podman v4.0 is not affected, so it makes + # sense to target only Podman v3.4 for a fix. + # + # The fix is simple, tag the image properly based on the expected tag from + # `share/image-id.txt` and delete the incorrect tag. + # + # [1] https://github.com/containers/podman/issues/16490 + if get_runtime_name() == "podman" and get_runtime_version() == (3, 4): + expected_tag = get_expected_tag() + bad_tag = f"localhost/{expected_tag}:latest" + good_tag = f"{CONTAINER_NAME}:{expected_tag}" + + log.debug( + f"Dangerzone images loaded in Podman v3.4 usually have an invalid tag." + " Fixing it..." + ) + add_image_tag(bad_tag, good_tag) + delete_image_tag(bad_tag) log.info("Successfully installed container image") diff --git a/dangerzone/isolation_provider/container.py b/dangerzone/isolation_provider/container.py index 0213cde..1cd80cc 100644 --- a/dangerzone/isolation_provider/container.py +++ b/dangerzone/isolation_provider/container.py @@ -97,6 +97,7 @@ class Container(IsolationProvider): f"Could not find a Dangerzone container image with tag '{expected_tag}'" ) for tag in old_tags: + tag = container_utils.CONTAINER_NAME + ":" + tag container_utils.delete_image_tag(tag) else: return True diff --git a/tests/isolation_provider/test_container.py b/tests/isolation_provider/test_container.py index 18fc58d..c8c9655 100644 --- a/tests/isolation_provider/test_container.py +++ b/tests/isolation_provider/test_container.py @@ -86,6 +86,10 @@ class TestContainer(IsolationProviderTest): self, provider: Container, fp: FakeProcess ) -> None: """When an image keep being not installed, it should return False""" + fp.register_subprocess( + ["podman", "version", "-f", "{{.Client.Version}}"], + stdout="4.0.0", + ) fp.register_subprocess( [container_utils.get_runtime(), "image", "ls"],