From be493dd6ea6c72cfca15ccc1ff1f4f4e67e99678 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/containerbuild.py | 6 +++++- test/test_manifest.py | 25 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/bib/cmd/bootc-image-builder/main.go b/bib/cmd/bootc-image-builder/main.go index 34752a70a..50dee3d83 100644 --- a/bib/cmd/bootc-image-builder/main.go +++ b/bib/cmd/bootc-image-builder/main.go @@ -178,25 +178,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, 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, nil) diff --git a/test/containerbuild.py b/test/containerbuild.py index e53c734e2..8652704c1 100644 --- a/test/containerbuild.py +++ b/test/containerbuild.py @@ -9,12 +9,16 @@ @contextmanager -def make_container(container_path): +def make_container(container_path, arch=None): # BIB only supports container tags, not hashes container_tag = "bib-test-" + "".join(random.choices(string.digits, k=12)) + arch_cmd = [] + if arch: + arch_cmd = ["--arch", arch] subprocess.check_call([ "podman", "build", "-t", container_tag, + *arch_cmd, container_path], encoding="utf8") yield container_tag subprocess.check_call(["podman", "rmi", container_tag]) 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