From 3c849434591eff35f79d299d20c99837b12041d8 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 12 Apr 2024 09:42:25 +0200 Subject: [PATCH] bib: check that architecture is expected arch When trying to build an image with an incompatible target arch bib will currently not error because the container resolver is not very strict about the architecture request. This commit fixes this by double checking that the resolved container is actually of the expected architecture. This requires https://github.com/osbuild/images/pull/585 --- bib/cmd/bootc-image-builder/main.go | 23 ++++++++++++++++------- test/test_manifest.py | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index a8ae6c66b..78ed5af6d 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -149,25 +149,34 @@ func makeManifest(c *ManifestConfig, cacheRoot string) (manifest.OSBuildManifest // (including the build-root) with the target arch then, it // is fast enough (given that it's mostly I/O and all I/O is // run naively via syscall translation) - hostArch := arch.Current().String() - targetArch := c.Architecture.String() + hostArch := arch.Current() + targetArch := c.Architecture - var resolver *container.Resolver - if targetArch != "" { - resolver = container.NewResolver(targetArch) + var wantedArch arch.Arch + if targetArch != arch.ARCH_UNSET { + wantedArch = targetArch } else { - resolver = container.NewResolver(hostArch) + wantedArch = hostArch } + // XXX: should NewResolver() take "arch.Arch"? + resolver := container.NewResolver(wantedArch.String()) containerSpecs := make(map[string][]container.Spec) for plName, sourceSpecs := range manifest.GetContainerSourceSpecs() { for _, c := range sourceSpecs { resolver.Add(c) } - containerSpecs[plName], err = resolver.Finish() + + specs, err := resolver.Finish() if err != nil { return nil, nil, fmt.Errorf("cannot resolve containers: %w", err) } + for _, spec := range specs { + if spec.Arch != wantedArch { + return nil, fmt.Errorf("image found is for unexpected architecture %q (expected %q), if that is intentional, please make sure --target-arch matches", spec.Arch, wantedArch) + } + } + containerSpecs[plName] = specs } mf, err := manifest.Serialize(depsolvedSets, containerSpecs, nil, depsolvedRepos) diff --git a/test/test_manifest.py b/test/test_manifest.py index 0b182fbba..7281abc40 100644 --- a/test/test_manifest.py +++ b/test/test_manifest.py @@ -1,4 +1,5 @@ import json +import platform import subprocess import textwrap @@ -109,3 +110,27 @@ def test_manifest_local_checks_containers_storage_works(tmp_path, build_containe f'--entrypoint=["/usr/bin/bootc-image-builder", "manifest", "--local", "localhost/{container_tag}"]', build_container, ], check=True, encoding="utf8") + + +@pytest.mark.skipif(platform.uname().machine != "x86_64", reason="cross build test only runs on x86") +def test_manifest_cross_arch_check(tmp_path, build_container): + cntf_path = tmp_path / "Containerfile" + cntf_path.write_text(textwrap.dedent("""\n + # build for x86_64 only + FROM scratch + """), encoding="utf8") + + with make_container(tmp_path, arch="x86_64") as container_tag: + with pytest.raises(subprocess.CalledProcessError) as exc: + subprocess.run([ + "podman", "run", "--rm", + "--privileged", + "-v", "/var/lib/containers/storage:/var/lib/containers/storage", + "--security-opt", "label=type:unconfined_t", + f'--entrypoint=["/usr/bin/bootc-image-builder", "manifest",\ + "--target-arch=aarch64", "--local", \ + "localhost/{container_tag}"]', + build_container, + ], check=True, capture_output=True, encoding="utf8") + # XXX: make more precise + assert "unexpected architecture" in exc.value.stderr