Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 72 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,8 @@ jobs:
bootloader: ["grub", "systemd"]
boot_type: ["bls", "uki"]
seal_state: ["sealed", "unsealed"]

exclude:
# centos-9 fails with EUCLEAN (https://github.com/bootc-dev/bootc/issues/1812)
# See: https://github.com/bootc-dev/bcvk/pull/204
# https://github.com/bootc-dev/bootc/issues/1812
- test_os: centos-9
variant: composefs
- seal_state: "sealed"
Expand Down Expand Up @@ -385,6 +383,76 @@ jobs:
name: "tmt-log-${{ matrix.test_os }}-${{ matrix.variant }}-upgrade-${{ env.ARCH }}"
path: /var/tmp/tmt

# Test readonly behaviour with baseconfigs (transient mounts) baked into the image.
# Composefs-only: setup-root-conf.toml is a composefs concept; ostree uses a
# different config format (prepare-root.conf) and is not covered here.
# Runs once per distro × baseconfig — no bootloader/filesystem/boot_type matrix.
test-baseconfigs:
if: needs.compute-ci-level.outputs.run_heavy == 'true'
needs: [compute-ci-level, package]
strategy:
fail-fast: false
matrix:
test_os: ${{ fromJson(needs.compute-ci-level.outputs.integration_os_matrix) }}
baseconfigs: ["etc-transient", "root-transient", "var-volatile"]

runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v6
- name: Bootc Ubuntu Setup
uses: bootc-dev/actions/bootc-ubuntu-setup@main
with:
libvirt: true
- name: Install tmt
run: pip install --user "tmt[provision-virtual]"

- name: Setup env
run: |
BASE=$(just pullspec-for-os base ${{ matrix.test_os }})
echo "BOOTC_base=${BASE}" >> $GITHUB_ENV
echo "BOOTC_variant=composefs" >> $GITHUB_ENV
echo "BOOTC_baseconfigs=${{ matrix.baseconfigs }}" >> $GITHUB_ENV
echo "RUST_BACKTRACE=full" >> $GITHUB_ENV

- name: Download package artifacts
uses: actions/download-artifact@v8
with:
name: packages-${{ matrix.test_os }}
path: target/packages/

- name: Build container with baseconfig
run: BOOTC_SKIP_PACKAGE=1 just build

- name: Build upgrade image
run: just _build-upgrade-image

- name: Run TMT readonly tests
run: |
cargo xtask run-tmt \
--env=BOOTC_variant=composefs \
--env=BOOTC_baseconfigs=${{ matrix.baseconfigs }} \
--composefs-backend --bootloader=grub --filesystem=ext4 \
--seal-state=unsealed --boot-type=bls \
--upgrade-image=localhost/bootc-upgrade \
localhost/bootc readonly
just clean-local-images

- name: Disk usage summary
if: always()
run: |
echo "### Disk usage" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
df -h >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"

- name: Archive TMT logs
if: always()
uses: actions/upload-artifact@v7
with:
name: "tmt-log-${{ matrix.test_os }}-composefs-baseconfigs-${{ matrix.baseconfigs }}-${{ env.ARCH }}"
path: /var/tmp/tmt

# Test bootc install on Fedora CoreOS (separate job to avoid disk space issues
# when run in the same job as test-integration).
# Uses fedora-43 as it's the current stable Fedora release matching CoreOS.
Expand Down Expand Up @@ -471,7 +539,7 @@ jobs:
# Accepts 'skipped' as success so that merge_group-only jobs don't block PRs.
required-checks:
if: always()
needs: [compute-ci-level, cargo-deny, validate, install-tests, docs, package, test-integration, test-upgrade, test-container-export]
needs: [compute-ci-level, cargo-deny, validate, install-tests, docs, package, test-integration, test-upgrade, test-baseconfigs, test-container-export]
runs-on: ubuntu-latest
steps:
- name: Check all jobs
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ FROM base as base-penultimate
ARG variant
ARG bootloader
ARG boot_type
ARG baseconfigs=""

# Switch to a signed systemd-boot, if configured
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
Expand Down Expand Up @@ -251,6 +252,10 @@ ARG rootfs=""
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/configure-rootfs "${variant}" "${rootfs}"
# Inject base configuration (e.g. transient-etc, transient-root) before dracut runs
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
/run/packaging/inject-baseconfig "${variant}" "${baseconfigs}"
# Override with our built package
RUN --network=none --mount=type=tmpfs,target=/run --mount=type=tmpfs,target=/tmp \
--mount=type=bind,from=packaging,src=/,target=/run/packaging \
Expand Down
33 changes: 31 additions & 2 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ filesystem := env("BOOTC_filesystem", "ext4")
boot_type := env("BOOTC_boot_type", "bls")
# Only used for composefs tests
seal_state := env("BOOTC_seal_state", "unsealed")
# Baseconfigs to inject into the image for testing (e.g. "etc-transient" or "root-transient")
baseconfigs := env("BOOTC_baseconfigs", "")
# Base container image to build from
base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10")
# Buildroot base image
Expand All @@ -56,18 +58,21 @@ no_auto_local_deps := env("BOOTC_no_auto_local_deps", "")
# Internal variables
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"
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 { "" }
# filesystem arg: required for bootc container ukify to allow missing fsverity
base_buildargs := generic_buildargs + " " + _extra_src_args \
+ " --build-arg=base=" + base \
+ " --build-arg=variant=" + variant \
+ " --build-arg=bootloader=" + bootloader \
+ " --build-arg=boot_type=" + boot_type \
+ " --build-arg=seal_state=" + seal_state \
+ " --build-arg=filesystem=" + filesystem # required for bootc container ukify to allow missing fsverity
+ " --build-arg=filesystem=" + filesystem \
+ " --build-arg=baseconfigs=" + baseconfigs
buildargs := base_buildargs \
+ " --cap-add=all --security-opt=label=type:container_runtime_t --device /dev/fuse" \
+ " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt"
Expand Down Expand Up @@ -266,7 +271,31 @@ test-container-export: build
# Run tmt tests without rebuilding (for fast iteration)
[group('testing')]
test-tmt-nobuild *ARGS:
cargo xtask run-tmt --env=BOOTC_variant={{variant}} --upgrade-image={{upgrade_img}} {{base_img}} {{ARGS}}
cargo xtask run-tmt --env=BOOTC_variant={{variant}} {{_baseconfigs_env}} --upgrade-image={{upgrade_img}} {{base_img}} {{ARGS}}

# Run readonly tests with a baseconfig baked into the image at build time.
# Requires composefs variant. Example: just variant=composefs test-tmt-baseconfig root-transient
[group('testing')]
test-tmt-baseconfig baseconfig *ARGS:
just variant=composefs baseconfigs={{baseconfig}} build
just variant=composefs baseconfigs={{baseconfig}} _build-upgrade-image
cargo xtask run-tmt \
--env=BOOTC_variant=composefs \
--env=BOOTC_baseconfigs={{baseconfig}} \
--upgrade-image={{upgrade_img}} \
--composefs-backend \
--bootloader={{bootloader}} \
--filesystem={{filesystem}} \
--boot-type={{boot_type}} \
--seal-state={{seal_state}} \
{{base_img}} readonly {{ARGS}}

# Run readonly tests for all standard baseconfigs
[group('testing')]
test-baseconfigs *ARGS:
just test-tmt-baseconfig etc-transient {{ARGS}}
just test-tmt-baseconfig root-transient {{ARGS}}
just test-tmt-baseconfig var-volatile {{ARGS}}

# Run tmt tests on Fedora CoreOS
[group('testing')]
Expand Down
61 changes: 61 additions & 0 deletions contrib/packaging/inject-baseconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash
# Inject base configuration files for CI testing of transient-root/etc/var configurations.
# Arguments: $1=variant, $2=baseconfigs (comma-separated, may be empty)
set -xeuo pipefail

VARIANT="${1:-}"
BASECONFIGS="${2:-}"

# No-op if no baseconfigs specified
if [ -z "${BASECONFIGS}" ]; then
exit 0
fi

# setup-root-conf.toml is composefs-specific; ostree uses prepare-root.conf
# which has a different (INI) format and different option names.
case "${VARIANT}" in
composefs*)
TARGET="/usr/lib/composefs/setup-root-conf.toml"
;;
*)
echo "inject-baseconfig: baseconfigs not supported for variant '${VARIANT}'" >&2
exit 1
;;
esac

mkdir -p "$(dirname "${TARGET}")"

# Split on commas and process each token
IFS=',' read -ra TOKENS <<< "${BASECONFIGS}"
for raw_token in "${TOKENS[@]}"; do
# Trim leading/trailing spaces
token="${raw_token#"${raw_token%%[![:space:]]*}"}"
token="${token%"${token##*[![:space:]]}"}"

[ -z "${token}" ] && continue

case "${token}" in
etc-transient)
printf '[etc]\ntransient = true\n' >> "${TARGET}"
;;
root-transient)
printf '[root]\ntransient = true\n' >> "${TARGET}"
;;
var-volatile)
# Mount /var as a fresh tmpfs on every boot via systemd.volatile=state.
# bootc-root-setup detects this karg in the initramfs and automatically
# skips the /var state bind-mount, leaving /var as an empty directory
# from the composefs image. systemd-fstab-generator then mounts a fresh
# tmpfs there at local-fs.target. Using a plain tmpfs avoids the
# overlayfs-on-overlayfs restriction that breaks tools like podman which
# use overlayfs under /var/lib/containers.
mkdir -p /usr/lib/bootc/kargs.d
printf 'kargs = ["systemd.volatile=state"]\n' \
> /usr/lib/bootc/kargs.d/50-var-volatile.toml
;;
*)
echo "Unknown baseconfig: ${token}" >&2
exit 1
;;
esac
done
1 change: 1 addition & 0 deletions crates/initramfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ rustix.workspace = true
serde = { workspace = true, features = ["derive"] }
composefs-ctl.workspace = true
toml.workspace = true
tracing.workspace = true
fn-error-context.workspace = true
bootc-kernel-cmdline = { path = "../kernel_cmdline", version = "0.0.0" }

Expand Down
9 changes: 9 additions & 0 deletions crates/initramfs/dracut/module-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,13 @@ install() {
mkdir -p "${initdir}${systemdsystemunitdir}/initrd-root-fs.target.wants"
ln_r "${systemdsystemunitdir}/${service}" \
"${systemdsystemunitdir}/initrd-root-fs.target.wants/${service}"

# Install the host's setup-root-conf.toml if present so that
# per-image composefs mount configuration (e.g. etc.transient) is
# embedded in the initramfs without requiring manual --include flags.
# Use '[[ -e ]] && inst_simple' rather than inst_if_exists, which is
# not available in all dracut invocation contexts (e.g. explicit
# dracut --force in a Containerfile RUN layer).
[[ -e /usr/lib/composefs/setup-root-conf.toml ]] && \
inst_simple /usr/lib/composefs/setup-root-conf.toml
}
Loading
Loading