diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc45584b80..9dffa0f21f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,7 +154,7 @@ jobs: - name: Fetch external dependencies (with retry) run: just build-fetch - - name: Integration tests + - name: Build images and test binaries run: | set -xeu # Build images as regular user, then copy to root's podman storage @@ -168,13 +168,19 @@ jobs: # Build test binaries before any sudo commands to avoid cargo permission issues cargo build --release -p tests-integration + cargo build --release -p system-reinstall-bootc sudo podman build -t localhost/bootc-fsverity -f ci/Containerfile.install-fsverity df -h / sudo install -m 0755 target/release/tests-integration /usr/bin/bootc-integration-tests + sudo install -m 0755 target/release/system-reinstall-bootc /usr/bin/system-reinstall-bootc sudo rm target -rf df -h / + + - name: Integration tests + run: | + set -xeu # The ostree-container tests sudo podman run --privileged --pid=host -v /:/run/host -v $(pwd):/src:ro -v /var/tmp:/var/tmp \ --tmpfs /var/lib/containers \ @@ -187,14 +193,10 @@ jobs: # inspect system state after the install tests. sudo lsblk sudo mount - - # system-reinstall-bootc tests - cargo build --release -p system-reinstall-bootc # not sure why this is missing in the ubuntu image but just creating this directory allows the tests to pass sudo mkdir -p /run/sshd - sudo install -m 0755 target/release/system-reinstall-bootc /usr/bin/system-reinstall-bootc # These tests may mutate the system live so we can't run in parallel sudo bootc-integration-tests system-reinstall localhost/bootc --test-threads=1 @@ -499,6 +501,9 @@ jobs: name: packages-${{ matrix.test_os }} path: target/packages/ + - name: Fetch external dependencies (with retry) + run: BOOTC_SKIP_PACKAGE=1 just build-fetch + - name: Build container with baseconfig run: BOOTC_SKIP_PACKAGE=1 just build @@ -602,7 +607,15 @@ jobs: name: packages-centos-10 path: target/packages/ - - name: Build and run container export test + - name: Fetch external dependencies (with retry) + run: BOOTC_SKIP_PACKAGE=1 just build-fetch + + - name: Build container and fetch Anaconda ISO + run: | + BOOTC_SKIP_PACKAGE=1 just build + BOOTC_SKIP_PACKAGE=1 just fetch-anaconda-iso + + - name: Run container export test run: | BOOTC_SKIP_PACKAGE=1 just test-container-export diff --git a/Justfile b/Justfile index 86f14dd278..1e3662e651 100644 --- a/Justfile +++ b/Justfile @@ -60,7 +60,13 @@ nocache := env("BOOTC_nocache", "") _nocache_arg := if nocache != "" { "--no-cache" } else { "" } _baseconfigs_env := if baseconfigs != "" { "--env=BOOTC_baseconfigs=" + baseconfigs } else { "" } testimage_label := "bootc.testimage=1" -lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest" +lbi_images := "quay.io/curl/curl:latest quay.io/curl/curl-base:latest docker.io/library/alpine:latest" +# Extra images pre-pulled on the GHA host so they are available via --bind-storage-ro +# inside test VMs without hitting the registry mid-test: +# bib_image: used by test-33-bib-build (needs --bind-storage-ro on plan-33) +# lbi_switch_images: additional bound images used by test-21-logically-bound-switch +bib_image := "quay.io/centos-bootc/bootc-image-builder:latest" +lbi_switch_images := "docker.io/library/alpine:3.19 docker.io/library/alpine:3.18 docker.io/library/alpine:latest" fedora-coreos := "quay.io/fedora/fedora-coreos:testing-devel" generic_buildargs := "" _extra_src_args := if extra_src != "" { "-v " + extra_src + ":/run/extra-src:ro --security-opt=label=disable" } else { "" } @@ -134,6 +140,15 @@ build-fetch: _keygen package for img in {{lbi_images}}; do retry podman pull -q "$img" done + # Pull images that are needed at runtime inside test VMs via --bind-storage-ro. + # These are NOT baked into the test container image; instead they are made + # available to the VM through the virtiofs host-storage mount that bcvk + # sets up when a plan requests try_bind_storage. + # bib_image: bootc-image-builder, used by plan-33-bib-build + # lbi_switch_images: bound images used by plan-21-logically-bound-switch + for img in {{bib_image}} {{lbi_switch_images}}; do + retry podman pull -q "$img" + done pkg_path=$(realpath target/packages) @@ -186,6 +201,7 @@ build-sealed: [group('core')] test-tmt *ARGS: build @just _build-upgrade-image + @just _build-selinux-policy-image @just test-tmt-nobuild {{ARGS}} # Split out from `test-container` because, unlike the container integration tests, @@ -261,9 +277,11 @@ validate: cargo xtask update-generated direct --check podman build {{base_buildargs}} --target validate-post-build . -# Test container export via Anaconda liveimg install in a QEMU VM +# Fetch the Anaconda boot ISO needed for the container export test. +# Run this as an explicit init step (with retry) before test-container-export +# so that transient network failures are isolated from the actual test run. [group('testing')] -test-container-export: build +fetch-anaconda-iso: build #!/bin/bash set -xeuo pipefail iso=target/anaconda-test/boot.iso @@ -279,7 +297,20 @@ test-container-export: build echo "Unsupported OS: ${ID}-${VERSION_ID}" >&2; exit 1 ;; esac mkdir -p target/anaconda-test - curl -L --retry 3 --progress-bar -o "$iso" "$url" + curl -L --retry 5 --retry-delay 30 --progress-bar -o "$iso" "$url" + fi + +# Test container export via Anaconda liveimg install in a QEMU VM. +# Requires the ISO to already be present; run `just fetch-anaconda-iso` first +# (or let the CI "Fetch Anaconda boot ISO" step handle it). +[group('testing')] +test-container-export: build + #!/bin/bash + set -xeuo pipefail + iso=target/anaconda-test/boot.iso + if [ ! -f "$iso" ]; then + echo "ERROR: $iso not found. Run 'just fetch-anaconda-iso' first." >&2 + exit 1 fi cargo run -p tests-integration -- anaconda-test --iso "$iso" {{base_img}} @@ -519,6 +550,15 @@ _build-upgrade-image: _build-upgrade-source-image: podman build --build-arg=base={{base}} --build-arg=variant={{variant}} -t {{upgrade_source_img}} -f tmt/tests/Dockerfile.upgrade-source . +# Build the pre-baked SELinux policy derived image used by test-29. +# Extends localhost/bootc with selinux-policy-devel + a custom policy module already +# installed, so the test VM does not need network access to dnf-install those tools. +# The resulting image is exposed to the test VM via --bind-storage-ro. +selinux_policy_img := base_img + "-selinux-tools" + +_build-selinux-policy-image: + podman build -t {{selinux_policy_img}} -f hack/Containerfile.selinux-policy . + # Copy an image from user podman storage to root's podman storage # This allows building as regular user then running privileged tests [group('testing')] @@ -559,6 +599,6 @@ copy-to-rootful $image: copy-lbi-to-rootful: #!/bin/bash set -euxo pipefail - for img in {{lbi_images}}; do + for img in {{lbi_images}} {{bib_image}} {{lbi_switch_images}} {{selinux_policy_img}}; do just copy-to-rootful "$img" done diff --git a/crates/xtask/src/tmt.rs b/crates/xtask/src/tmt.rs index a46c7b153b..5fa51424c7 100644 --- a/crates/xtask/src/tmt.rs +++ b/crates/xtask/src/tmt.rs @@ -27,6 +27,7 @@ const FIELD_FIXME_SKIP_IF_UKI: &str = "fixme_skip_if_uki"; // bcvk options const BCVK_OPT_BIND_STORAGE_RO: &str = "--bind-storage-ro"; +const BCVK_OPT_RESTRICT_NETWORK: &str = "--restrict-network"; const ENV_BOOTC_UPGRADE_IMAGE: &str = "BOOTC_upgrade_image"; // Distro identifiers @@ -517,6 +518,10 @@ pub(crate) fn run_tmt(sh: &Shell, args: &RunTmtArgs) -> Result<()> { let mut opts = Vec::new(); + // Block outbound internet from the VM during test execution. + // Inbound SSH port-forward still works so tmt can reach the VM. + opts.push(BCVK_OPT_RESTRICT_NETWORK.to_string()); + // If test wants bind storage and distro supports it, add --bind-storage-ro if try_bind_storage && supports_bind_storage_ro { opts.push(BCVK_OPT_BIND_STORAGE_RO.to_string()); diff --git a/hack/Containerfile.selinux-policy b/hack/Containerfile.selinux-policy new file mode 100644 index 0000000000..91b56c7411 --- /dev/null +++ b/hack/Containerfile.selinux-policy @@ -0,0 +1,45 @@ +# Pre-built derived image used by test-29 (soft-reboot-selinux-policy). +# +# Building this in the CI build phase (network-allowed) avoids a live dnf +# install inside the test VM, which would be a network access mid-test. +# +# What this does: +# 1. Installs SELinux policy build tools into localhost/bootc +# 2. Compiles and installs a minimal custom policy module, which changes +# the compiled policy checksum relative to the base image +# 3. Cleans up build artifacts so the image passes standard lint checks +# +# The resulting image is exposed to the test VM via --bind-storage-ro and +# pulled into bootc storage before the switch/soft-reboot attempt. +FROM localhost/bootc + +# Install tools needed to build and install SELinux policy modules. +# The packages are available from the base image's own repos (no extra +# repo file needed: localhost/bootc is derived from a centos/fedora/rhel +# base that ships these in standard repositories). +RUN dnf install -y selinux-policy-devel checkpolicy policycoreutils \ + && dnf clean all \ + && rm -rf /var/log/dnf* /var/log/hawkey.log /var/log/rhsm \ + /var/cache/dnf /var/lib/dnf /var/lib/rhsm + +# Create a minimal SELinux policy module and install it. +# Installing a module changes the compiled policy checksum, which is exactly +# what test-29 needs to verify that soft-reboot is blocked when policies differ. +RUN < bootc_test_policy.te <<'EOF' +module bootc_test_policy 1.0; +require { + type unconfined_t; + class file { read write }; +} +type bootc_test_t; +EOF +checkmodule -M -m -o bootc_test_policy.mod bootc_test_policy.te +semodule_package -o bootc_test_policy.pp -m bootc_test_policy.mod +semodule -i bootc_test_policy.pp +rm -rf /tmp/bootc-test-policy +rm -rf /var/lib/sepolgen /var/cache/ldconfig +EORUN diff --git a/hack/lbi/podman.image b/hack/lbi/podman.image index cb37cc613e..234e226391 100644 --- a/hack/lbi/podman.image +++ b/hack/lbi/podman.image @@ -1,2 +1,2 @@ [Image] -Image=registry.access.redhat.com/ubi9/podman:latest +Image=docker.io/library/alpine:latest diff --git a/hack/packages.txt b/hack/packages.txt index 8a1f51b517..61ae1b3ac3 100644 --- a/hack/packages.txt +++ b/hack/packages.txt @@ -13,3 +13,5 @@ dosfstools e2fsprogs # Required by bib-build test qemu-img +# Required by 030-test-composefs.nu (pre-fetches busybox OCI image during build) +skopeo diff --git a/hack/provision-fetch.sh b/hack/provision-fetch.sh index ef2ee9e73c..429a36f798 100755 --- a/hack/provision-fetch.sh +++ b/hack/provision-fetch.sh @@ -89,3 +89,13 @@ fi dnf clean all # Clean logs and caches rm /var/log/* /var/cache /var/lib/{dnf,rpm-state,rhsm} -rf + +# Pre-fetch the busybox OCI image for the composefs cfs pull test +# (030-test-composefs.nu). We save it as an OCI layout so the test can +# use "oci:" transport instead of "docker://" and avoid a live registry +# pull inside the test VM. This runs after dnf clean so it doesn't affect +# the dnf cache, but still within the network-allowed fetch stage. +mkdir -p /usr/share/bootc-test/busybox-oci +skopeo copy --retry-times 5 \ + docker://docker.io/library/busybox:latest \ + oci:/usr/share/bootc-test/busybox-oci diff --git a/tmt/plans/integration.fmf b/tmt/plans/integration.fmf index 271d862efe..db68585de7 100644 --- a/tmt/plans/integration.fmf +++ b/tmt/plans/integration.fmf @@ -31,13 +31,14 @@ prepare: # Work around https://github.com/bootc-dev/bootc/issues/1896 - cd bootc && rpm2cpio *.src.rpm > pkg.cpio && cpio -idmv < pkg.cpio && rm pkg.cpio && rm -f *-vendor.tar.zstd && zstd -d *.tar.zstd && tar -xvf *.tar -C . --strip-components=1 && ls -al - pwd && ls -al && cd bootc/hack && ./provision-packit.sh + - cp bootc/hack/packit-reboot.yml /tmp/packit-reboot.yml when: running_env != image_mode # tmt-reboot and reboot do not work in this case # reboot in ansible is the only way to reboot in tmt prepare - how: ansible order: 99 playbook: - - https://github.com/bootc-dev/bootc/raw/refs/heads/main/hack/packit-reboot.yml + - /tmp/packit-reboot.yml when: running_env != image_mode execute: how: tmt @@ -64,6 +65,7 @@ execute: how: fmf test: - /tmt/tests/tests/test-21-logically-bound-switch + extra-try_bind_storage: true extra-fixme_skip_if_composefs: true /plan-22-logically-bound-install: @@ -136,6 +138,7 @@ execute: how: fmf test: - /tmt/tests/tests/test-29-soft-reboot-selinux-policy + extra-try_bind_storage: true extra-fixme_skip_if_uki: true /plan-30-install-unified-flag: @@ -144,6 +147,7 @@ execute: how: fmf test: - /tmt/tests/tests/test-30-install-unified-flag + extra-try_bind_storage: true extra-fixme_skip_if_composefs: true /plan-31-switch-mutate-in-place: @@ -182,6 +186,7 @@ execute: how: fmf test: - /tmt/tests/tests/test-33-bib-build + extra-try_bind_storage: true extra-fixme_skip_if_composefs: true /plan-34-user-agent: @@ -249,6 +254,7 @@ execute: how: fmf test: - /tmt/tests/tests/test-40-install-karg-delete + extra-try_bind_storage: true extra-fixme_skip_if_composefs: true /plan-41-composefs-gc-uki: diff --git a/tmt/tests/booted/readonly/010-test-bootc-container-store.nu b/tmt/tests/booted/readonly/010-test-bootc-container-store.nu index 4786754695..004f3f6e2e 100644 --- a/tmt/tests/booted/readonly/010-test-bootc-container-store.nu +++ b/tmt/tests/booted/readonly/010-test-bootc-container-store.nu @@ -33,7 +33,7 @@ if not $has_storage { # And verify this works bootc image cmd list -q o>/dev/null - bootc image cmd pull busybox + bootc image cmd pull oci:/usr/share/bootc-test/busybox-oci podman --storage-opt=additionalimagestore=/usr/lib/bootc/storage image exists busybox # Images in bootc storage should be listed with type "unified" diff --git a/tmt/tests/booted/readonly/030-test-composefs.nu b/tmt/tests/booted/readonly/030-test-composefs.nu index 801c5a7eec..597e868d0a 100644 --- a/tmt/tests/booted/readonly/030-test-composefs.nu +++ b/tmt/tests/booted/readonly/030-test-composefs.nu @@ -65,7 +65,7 @@ if $is_composefs { # we can't get from `bootc internals cfs ...` mkdir /var/tmp/sysroot/composefs bootc internals cfs --insecure --repo /var/tmp/sysroot/composefs init - bootc internals cfs --insecure --repo /var/tmp/sysroot/composefs oci pull docker://busybox busybox + bootc internals cfs --insecure --repo /var/tmp/sysroot/composefs oci pull oci:/usr/share/bootc-test/busybox-oci busybox test -L /var/tmp/sysroot/composefs/streams/refs/oci/busybox } diff --git a/tmt/tests/booted/tap.nu b/tmt/tests/booted/tap.nu index b4f0dd23d3..ea3dfcd34d 100644 --- a/tmt/tests/booted/tap.nu +++ b/tmt/tests/booted/tap.nu @@ -39,7 +39,7 @@ export def get_target_image [] { # If map not found, use default centos-9 image if not ($map_path | path exists) { - return "docker://quay.io/centos-bootc/centos-bootc:stream9" + return "containers-storage:quay.io/centos-bootc/centos-bootc:stream9" } let image_map = (open $map_path) @@ -47,9 +47,9 @@ export def get_target_image [] { let image = $image_map.base | get -i $key if ($image | is-empty) { # Fallback to centos-9 if key not found - $"docker://($image_map.base.centos-9)" + $"containers-storage:($image_map.base.centos-9)" } else { - $"docker://($image)" + $"containers-storage:($image)" } } diff --git a/tmt/tests/booted/test-bib-build.nu b/tmt/tests/booted/test-bib-build.nu index 765698204f..670e3b1268 100644 --- a/tmt/tests/booted/test-bib-build.nu +++ b/tmt/tests/booted/test-bib-build.nu @@ -6,6 +6,7 @@ # - qemu-img # extra: # fixme_skip_if_composefs: true +# try_bind_storage: true # # This test validates that bootc-image-builder (bib) can successfully # create disk images from the current booted image. This is a critical diff --git a/tmt/tests/booted/test-install-karg-delete.nu b/tmt/tests/booted/test-install-karg-delete.nu index ca9364333a..1ccd382ada 100644 --- a/tmt/tests/booted/test-install-karg-delete.nu +++ b/tmt/tests/booted/test-install-karg-delete.nu @@ -3,6 +3,7 @@ # summary: Test bootc install --karg-delete # duration: 30m # extra: +# try_bind_storage: true # fixme_skip_if_composefs: true # use std assert diff --git a/tmt/tests/booted/test-install-unified-flag.nu b/tmt/tests/booted/test-install-unified-flag.nu index e00ecb01ac..eaed8e6a6d 100644 --- a/tmt/tests/booted/test-install-unified-flag.nu +++ b/tmt/tests/booted/test-install-unified-flag.nu @@ -1,5 +1,6 @@ # number: 30 # extra: +# try_bind_storage: true # fixme_skip_if_composefs: true # tmt: # summary: Test bootc install with experimental unified storage flag diff --git a/tmt/tests/booted/test-logically-bound-install.nu b/tmt/tests/booted/test-logically-bound-install.nu index d2c36fcbfc..0d5864ffbd 100644 --- a/tmt/tests/booted/test-logically-bound-install.nu +++ b/tmt/tests/booted/test-logically-bound-install.nu @@ -12,7 +12,7 @@ use tap.nu let expected_images = [ "quay.io/curl/curl:latest", "quay.io/curl/curl-base:latest", - "registry.access.redhat.com/ubi9/podman:latest" # this image is signed + "docker.io/library/alpine:latest" ] def validate_images [images: list] { diff --git a/tmt/tests/booted/test-logically-bound-switch.nu b/tmt/tests/booted/test-logically-bound-switch.nu index 298d7ff86a..3d59c20e8c 100644 --- a/tmt/tests/booted/test-logically-bound-switch.nu +++ b/tmt/tests/booted/test-logically-bound-switch.nu @@ -4,6 +4,7 @@ # duration: 30m # extra: # fixme_skip_if_composefs: true +# try_bind_storage: true # # This test does: # bootc image switch bootc-bound-image @@ -32,6 +33,19 @@ def initial_setup [] { bootc image copy-to-storage podman images podman image inspect localhost/bootc | from json + + # Pre-seed the bound images used by this test into bootc's own storage. + # The images are pre-pulled on the CI host (via build-fetch) and exposed + # inside the VM through --bind-storage-ro (virtiofs additionalimagestore). + # Copying them into bootc storage now avoids a live registry pull when + # bootc resolves bound image declarations during `bootc switch`. + for img in [ + "docker.io/library/alpine:3.19", + "docker.io/library/alpine:3.18", + "docker.io/library/alpine:latest", + ] { + bootc image pull-from-default-storage $img + } } def build_image [name images containers] { @@ -93,7 +107,7 @@ def first_boot [] { # build a bootc image that includes bound images let images = [ - { "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.4", "name": "ubi-minimal" }, + { "bound": true, "image": "docker.io/library/alpine:3.19", "name": "ubi-minimal" }, { "bound": false, "image": "quay.io/centos-bootc/centos-bootc:stream9", "name": "centos-bootc" } ] @@ -115,7 +129,7 @@ def second_boot [] { # verify images are still there after boot let images = [ - { "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.4", "name": "ubi-minimal" }, + { "bound": true, "image": "docker.io/library/alpine:3.19", "name": "ubi-minimal" }, { "bound": false, "image": "quay.io/centos-bootc/centos-bootc:stream9", "name": "centos-bootc" } ] @@ -127,7 +141,7 @@ def second_boot [] { # build a new bootc image with an additional bound image print "bootc upgrade with another bound image" let image_name = "localhost/bootc-bound" - let more_images = $images | append [{ "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.3", "name": "ubi-minimal-9-3" }] + let more_images = $images | append [{ "bound": true, "image": "docker.io/library/alpine:3.18", "name": "ubi-minimal-9-3" }] build_image $image_name $more_images $containers bootc upgrade verify_images $more_images $containers @@ -140,8 +154,8 @@ def third_boot [] { assert equal $booted.image.image localhost/bootc-bound let images = [ - { "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.4", "name": "ubi-minimal" }, - { "bound": true, "image": "registry.access.redhat.com/ubi9/ubi-minimal:9.3", "name": "ubi-minimal-9-3" }, + { "bound": true, "image": "docker.io/library/alpine:3.19", "name": "ubi-minimal" }, + { "bound": true, "image": "docker.io/library/alpine:3.18", "name": "ubi-minimal-9-3" }, { "bound": false, "image": "quay.io/centos-bootc/centos-bootc:stream9", "name": "centos-bootc" } ] diff --git a/tmt/tests/booted/test-soft-reboot-selinux-policy.nu b/tmt/tests/booted/test-soft-reboot-selinux-policy.nu index 1ebb11f177..422ff867fb 100644 --- a/tmt/tests/booted/test-soft-reboot-selinux-policy.nu +++ b/tmt/tests/booted/test-soft-reboot-selinux-policy.nu @@ -3,6 +3,7 @@ # summary: Test soft reboot with SELinux policy changes # duration: 30m # extra: +# try_bind_storage: true # fixme_skip_if_uki: true # # Verify that soft reboot is blocked when SELinux policies differ @@ -30,119 +31,28 @@ bootc status def initial_build [] { tap begin "Build base image and test soft reboot with SELinux policy change" - let td = mktemp -d - cd $td + # The derived image with a custom SELinux policy module pre-installed is + # built in the CI build phase (via `just _build-selinux-policy-image`) and + # exposed to this VM via --bind-storage-ro / STORAGE_OPTS additionalimagestore. + # Pull it into bootc's own storage before switching. + bootc image pull-from-default-storage localhost/bootc-selinux-tools - bootc image copy-to-storage - - # copy-to-storage does not copy repo file - # but OSCI gating test needs repo to install package - let os = open /usr/lib/os-release - | lines - | filter {|l| $l != "" and not ($l | str starts-with "#") } - | parse "{key}={value}" - | reduce {|it, acc| - $acc | upsert $it.key ($it.value | str trim -c '"') - } - mut repo_copy = "" - - if $os.ID == "rhel" { - cp /etc/yum.repos.d/rhel.repo . - $repo_copy = "COPY rhel.repo /etc/yum.repos.d/" - } else if $os.ID == "centos" { - let gpgkey = ( - open /etc/yum.repos.d/centos.repo - | lines - | find --regex '^gpgkey=' - | first - | split row "=" - | last - ) - - if ($gpgkey | is-empty) { - print -e "Error: Could not find gpgkey in /etc/yum.repos.d/centos.repo" - exit 1 - } - - # Enable latest repos to avoid version skew between - # installed image and building image - let repo_content = $"[compose-baseos] -name=CentOS Stream $releasever Compose BaseOS -baseurl=https://composes.stream.centos.org/stream-$releasever/production/latest-CentOS-Stream/compose/BaseOS/$basearch/os/ -gpgcheck=1 -enabled=1 -priority=1 -gpgkey=($gpgkey) -exclude=kernel-debug* kernel-uki-virt* - -[compose-appstream] -name=CentOS Stream $releasever Compose AppStream -baseurl=https://composes.stream.centos.org/stream-$releasever/production/latest-CentOS-Stream/compose/AppStream/$basearch/os/ -gpgcheck=1 -enabled=1 -priority=1 -gpgkey=($gpgkey) -exclude=kernel-debug* kernel-uki-virt* -" - $repo_content | save --force centos-compose.repo - - $repo_copy = "COPY centos-compose.repo /etc/yum.repos.d/" - } - - # Create a derived container that installs a custom SELinux policy module - # Installing a policy module will change the compiled policy checksum - # Following Colin's suggestion and the composefs-rs example - # We create a minimal policy module and install it - (tap make_uki_containerfile $" -FROM localhost/bootc as base -($repo_copy) - -# Install tools needed to build and install SELinux policy modules -RUN dnf install -y selinux-policy-devel checkpolicy policycoreutils - -# Create a minimal SELinux policy module that will change the policy checksum -# We install it to ensure it's part of the deployment filesystem -RUN < bootc_test_policy.te - echo 'require {' >> bootc_test_policy.te - echo ' type unconfined_t;' >> bootc_test_policy.te - echo ' class file { read write };' >> bootc_test_policy.te - echo '}' >> bootc_test_policy.te - echo 'type bootc_test_t;' >> bootc_test_policy.te - checkmodule -M -m -o bootc_test_policy.mod bootc_test_policy.te - semodule_package -o bootc_test_policy.pp -m bootc_test_policy.mod - semodule -i bootc_test_policy.pp - rm -rf /tmp/bootc-test-policy - # Clean up dnf cache and logs, and SELinux policy generation artifacts to satisfy lint checks - dnf clean all - rm -rf /var/log/dnf* /var/log/hawkey.log /var/log/rhsm - rm -rf /var/cache/dnf /var/lib/dnf - rm -rf /var/lib/sepolgen /var/lib/rhsm /var/cache/ldconfig -EORUN -") | save Dockerfile - - # Build the derived image - podman build --quiet -t localhost/bootc-derived-policy . - # Verify soft reboot preparation hasn't happened yet assert (not ("/run/nextroot" | path exists)) - + # Try to soft reboot - this should fail because policies differ - bootc switch --soft-reboot=auto --transport containers-storage localhost/bootc-derived-policy + bootc switch --soft-reboot=auto --transport containers-storage localhost/bootc-selinux-tools let st = bootc status --json | from json - + # Verify staged deployment exists assert ($st.status.staged != null) "Expected staged deployment to exist" - + # The staged deployment should NOT be soft-reboot capable because policies differ assert (not $st.status.staged.softRebootCapable) "Expected soft reboot to be blocked due to SELinux policy difference, but softRebootCapable is true" - + # Verify soft reboot preparation didn't happen assert (not ("/run/nextroot" | path exists)) "Soft reboot should not be prepared when policies differ" - + # Do a full reboot tmt-reboot } @@ -150,12 +60,12 @@ EORUN # The second boot; verify we're in the derived image def second_boot [] { tap begin "Verify deployment with different SELinux policy" - + # Verify we're in the new deployment let st = bootc status --json | from json let booted = $st.status.booted.image - assert ($booted.image.image | str contains "bootc-derived-policy") $"Expected booted image to contain 'bootc-derived-policy', got: ($booted.image.image)" - + assert ($booted.image.image | str contains "bootc-selinux-tools") $"Expected booted image to contain 'bootc-selinux-tools', got: ($booted.image.image)" + tap ok } diff --git a/tmt/tests/lbi/usr/share/containers/systemd/podman.image b/tmt/tests/lbi/usr/share/containers/systemd/podman.image index cb37cc613e..234e226391 100644 --- a/tmt/tests/lbi/usr/share/containers/systemd/podman.image +++ b/tmt/tests/lbi/usr/share/containers/systemd/podman.image @@ -1,2 +1,2 @@ [Image] -Image=registry.access.redhat.com/ubi9/podman:latest +Image=docker.io/library/alpine:latest