feat: add remove-signatures option to container-deploy stage

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 <mmartinv@redhat.com>
This commit is contained in:
Miguel Martín 2024-10-18 12:44:26 +02:00 committed by Michael Vogt
parent 8429acf7e3
commit dd16c2b769
3 changed files with 46 additions and 5 deletions

View file

@ -36,6 +36,7 @@ def main(inputs, tree, options):
images = containers.parse_containers_input(inputs) images = containers.parse_containers_input(inputs)
assert len(images) == 1 assert len(images) == 1
image = list(images.values())[0] 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 # skopeo needs /var/tmp but the bwrap env is minimal and may not have it
os.makedirs("/var/tmp", mode=0o1777, exist_ok=True) os.makedirs("/var/tmp", mode=0o1777, exist_ok=True)
@ -47,11 +48,11 @@ def main(inputs, tree, options):
with contextlib.ExitStack() as cm: with contextlib.ExitStack() as cm:
cm.callback(subprocess.run, ["podman", "rmi", image_tag], check=True) cm.callback(subprocess.run, ["podman", "rmi", image_tag], check=True)
with containers.container_source(image) as (_, source): with containers.container_source(image) as (_, source):
subprocess.run( cmd = ["skopeo", "copy"]
["skopeo", "copy", source, if remove_signatures:
f"containers-storage:{image_tag}"], cmd.append("--remove-signatures")
check=True, cmd.extend([source, f"containers-storage:{image_tag}"])
) subprocess.run(cmd, check=True)
with mount_container(image_tag) as img: with mount_container(image_tag) as img:
subprocess.run(["cp", "-a", f"{img}/.", f"{tree}/"], check=True) subprocess.run(["cp", "-a", f"{img}/.", f"{tree}/"], check=True)
# postprocess the tree, would be nicer to filter before already # postprocess the tree, would be nicer to filter before already

View file

@ -27,6 +27,11 @@
"items": { "items": {
"type": "string" "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."
} }
} }
} }

View file

@ -92,3 +92,38 @@ def test_container_deploy_error(stage_module):
pass pass
assert "some msg on stdout" not in str(exp.value) assert "some msg on stdout" not in str(exp.value)
assert "other error on stderr" 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]