diff --git a/dangerzone/container_utils.py b/dangerzone/container_utils.py index 7c9dcb8..a6ef543 100644 --- a/dangerzone/container_utils.py +++ b/dangerzone/container_utils.py @@ -192,13 +192,22 @@ def container_pull(image: str) -> bool: return process.returncode == 0 -def get_local_image_hash(image: str) -> Optional[str]: +def get_local_image_digest(image: str) -> Optional[str]: """ Returns a image hash from a local image name """ - cmd = [get_runtime_name(), "image", "inspect", image, "-f", "{{.Digest}}"] + # Get the image hash from the podman images command, as + # podman inspect returns a the digest of the architecture-bound image + cmd = [get_runtime_name(), "images", image, "--format", "{{.Digest}}"] + log.debug(" ".join(cmd)) try: result = subprocess.run(cmd, capture_output=True, check=True) + lines = result.stdout.decode().strip().split("\n") + if len(lines) != 1: + raise errors.MultipleImagesFoundException( + f"Expected a single line of output, got {len(lines)} lines" + ) + return lines[0].replace("sha256:", "") except subprocess.CalledProcessError as e: return None else: diff --git a/dangerzone/errors.py b/dangerzone/errors.py index d8e1759..5abe187 100644 --- a/dangerzone/errors.py +++ b/dangerzone/errors.py @@ -126,6 +126,10 @@ class ImageNotPresentException(Exception): pass +class MultipleImagesFoundException(Exception): + pass + + class ImageInstallationException(Exception): pass diff --git a/dangerzone/updater/signatures.py b/dangerzone/updater/signatures.py index f0cacd2..65f855a 100644 --- a/dangerzone/updater/signatures.py +++ b/dangerzone/updater/signatures.py @@ -105,7 +105,7 @@ def verify_signature(signature: dict, image_hash: str, pubkey: str) -> bool: def new_image_release(image: str) -> bool: remote_hash = registry.get_manifest_hash(image) - local_hash = runtime.get_local_image_hash(image) + local_hash = runtime.get_local_image_digest(image) log.debug("Remote hash: %s", remote_hash) log.debug("Local hash: %s", local_hash) return remote_hash != local_hash @@ -181,7 +181,8 @@ def upgrade_container_image_airgapped(container_tar: str, pubkey: str) -> str: index_json["manifests"] = [ manifest for manifest in index_json["manifests"] - if manifest["annotations"].get("kind") != "dev.cosignproject.cosign/sigs" + if manifest["annotations"].get("kind") + in ("dev.cosignproject.cosign/imageIndex", "dev.cosignproject.cosign/image") ] with open(signature_filename, "rb") as f: @@ -317,7 +318,7 @@ def verify_local_image(image: str, pubkey: str) -> bool: """ log.info(f"Verifying local image {image} against pubkey {pubkey}") try: - image_hash = runtime.get_local_image_hash(image) + image_hash = runtime.get_local_image_digest(image) except subprocess.CalledProcessError: raise errors.ImageNotFound(f"The image {image} does not exist locally")