From ca5d8005a27dd7675bccdee95f982baf1a2b43c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20Mart=C3=ADn?= Date: Fri, 18 Oct 2024 12:44:26 +0200 Subject: [PATCH] feat: add remove-signatures option to container-deploy stage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add remove-signatures option to container-deploy stage. The option will be translated to --remove-signatures skopeo option and passed to skopeo when copying the container. This option must be set when deploying signed containers. Signed-off-by: Miguel Martín --- stages/org.osbuild.container-deploy | 11 +++--- stages/org.osbuild.container-deploy.meta.json | 5 +++ stages/test/test_container_deploy.py | 35 +++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/stages/org.osbuild.container-deploy b/stages/org.osbuild.container-deploy index 2a3bae8be8..29fe7b977b 100755 --- a/stages/org.osbuild.container-deploy +++ b/stages/org.osbuild.container-deploy @@ -36,6 +36,7 @@ def main(inputs, tree, options): images = containers.parse_containers_input(inputs) assert len(images) == 1 image = list(images.values())[0] + remove_signatures = options.get("remove-signatures") # skopeo needs /var/tmp but the bwrap env is minimal and may not have it os.makedirs("/var/tmp", mode=0o1777, exist_ok=True) @@ -47,11 +48,11 @@ def main(inputs, tree, options): with contextlib.ExitStack() as cm: cm.callback(subprocess.run, ["podman", "rmi", image_tag], check=True) with containers.container_source(image) as (_, source): - subprocess.run( - ["skopeo", "copy", source, - f"containers-storage:{image_tag}"], - check=True, - ) + cmd = ["skopeo", "copy"] + if remove_signatures: + cmd.append("--remove-signatures") + cmd.extend([source, f"containers-storage:{image_tag}"]) + subprocess.run(cmd, check=True) with mount_container(image_tag) as img: subprocess.run(["cp", "-a", f"{img}/.", f"{tree}/"], check=True) # postprocess the tree, would be nicer to filter before already diff --git a/stages/org.osbuild.container-deploy.meta.json b/stages/org.osbuild.container-deploy.meta.json index 97cbc29ebb..355249b0da 100644 --- a/stages/org.osbuild.container-deploy.meta.json +++ b/stages/org.osbuild.container-deploy.meta.json @@ -27,6 +27,11 @@ "items": { "type": "string" } + }, + "remove-signatures": { + "type": "boolean", + "default": false, + "description": "Do not copy signatures, if any, from source-image. Necessary when copying a signed image to a destination which does not support signatures." } } } diff --git a/stages/test/test_container_deploy.py b/stages/test/test_container_deploy.py index 748369afe0..a2fc6c5a93 100644 --- a/stages/test/test_container_deploy.py +++ b/stages/test/test_container_deploy.py @@ -92,3 +92,38 @@ def test_container_deploy_error(stage_module): pass assert "some msg on stdout" not in str(exp.value) assert "other error on stderr" in str(exp.value) + + +@pytest.mark.skipif(os.getuid() != 0, reason="needs root") +@pytest.mark.skipif(not has_executable("podman"), reason="no podman executable") +@pytest.mark.parametrize("remove_signatures", [True, False]) +def test_remove_signatures(tmp_path, stage_module, remove_signatures): + with make_container(tmp_path, {}) as cont_tag: + # export for the container-deploy stage + fake_oci_path = tmp_path / "fake-container" + subprocess.check_call([ + "podman", "save", + "--format=oci-archive", + f"--output={fake_oci_path}", + cont_tag, + ]) + inputs = make_fake_images_inputs(fake_oci_path, "some-name") + + fake_skopeo = textwrap.dedent("""\ + #! /bin/sh + /usr/bin/skopeo $@ + """) + + with osbuild.testutil.mock_command("skopeo", fake_skopeo) as args: + inputs = make_fake_images_inputs(fake_oci_path, "some-name") + options = { + "remove-signatures": remove_signatures, + } + output_dir = tmp_path / "output" + stage_module.main(inputs, output_dir, options) + if remove_signatures: + # Check that skopeo has --remove-signatures right after the copy subcommand + assert args.call_args_list[0][0:2] == ["copy", "--remove-signatures"] + else: + # Check that --remove-signatures is not present in the skopeo command + assert "--remove-signatures" not in args.call_args_list[0]